# options
options(stringsAsFactors = F)
knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)
knitr::opts_knit$set(progress = FALSE)



Figure 4A: Genetic map of the pluripotent proteome

# prepping data
peaks.esc_prot_annotated <- peaks.esc_prot %>%
  rename( protein_id = phenotype) %>%
  left_join(all.prots2) %>%
  mutate( same_chrom =  (peak_chr == gene_chr),
          diff = abs(midpoint - interp_bp_peak)) %>%
  mutate( local = ifelse( same_chrom &
                            diff < 10e06, TRUE, FALSE
    )) %>% 
  # removing the pQTL for the proteins that lack annotations.
  filter(!is.na(mgi_symbol)) 
peaks.esc_prot_annotated$cumsum_bp_peak <- peaks.esc_prot_annotated$interp_bp_peak + chrom_lens_offset[peaks.esc_prot_annotated$peak_chr]

Figure4A_data <- peaks.esc_prot_annotated %>% 
  filter( lod > 7.5) %>% 
  mutate( local = ifelse( local ==T, "Local", "Distant")) %>% 
  select(
    `Protein ID`= protein_id,
    `Offsetted QTL peak location (bp)` = cumsum_bp_peak,
    `Offsetted gene midpoint (bp)` = cumsum_bp_gene,
    `QTL peak (chr)` = peak_chr,
    `QTL peak (bp)` = interp_bp_peak,
    `MGI symbol` = mgi_symbol,
    `Gene start` = gene_start,
    `Gene end` = gene_end,
    `Gene chr` = gene_chr
  )


# graphical prep for chromosome locations
chroms <- c(as.character(1:19), "X")
chrom_lens <- c( 195431559, 182107670, 160017104, 156496071, 151833620, 149721874, 145434693, 129399468, 124582650, 130685419, 122078650, 120120622 ,120387272, 124867725, 104015452, 98180002, 94984432, 90672596, 61417310 , 171028300)
names(chrom_lens) <- chroms
chrom_lens_offset <- cumsum(chrom_lens) - chrom_lens
chrom_lens_midpt <- chrom_lens_offset + chrom_lens / 2

# prepping chromosome segments for coloring
chrom_segments <- tibble( start = 0, 
                          end = chrom_lens,
                          chr = chroms,
                          type = as.character(rep(c(0,1),10)))
chrom_segments$start <- chrom_segments$start+ chrom_lens_offset[chrom_segments$chr]
chrom_segments$end <- chrom_segments$end+ chrom_lens_offset[chrom_segments$chr]

# qtl colors
qtl.colors <- c( rna = "#228833", 
                 prot = "#4477AA", 
                 atac = "#EE6677",
                 shared = "#AA3377")

ggplot()+
  geom_rect( data = chrom_segments, aes( xmin =start, xmax = end, ymin = 0, ymax = max(end), fill = type), 
             inherit.aes = FALSE, alpha = 0.2, show.legend = FALSE)+
  scale_fill_manual(values = c("dark gray","white"))+
  geom_point(data = Figure4A_data, 
            aes( x =  `Offsetted QTL peak location (bp)`, 
                 y = `Offsetted gene midpoint (bp)`, 
                 text = paste0("Gene: ",`MGI symbol`, "\n","chr", `Gene chr`,":",`Gene start`,"-",`Gene end`, "\n",
                               "QTL position: chr", `QTL peak (chr)`, ":",`QTL peak (bp)`)
                 ),
            size = 2, 
            col =qtl.colors[["prot"]],
             inherit.aes = FALSE ,
            )+
  theme_pubclean(base_size = 16)+
  scale_x_discrete( name = "pQTL",
                    limits = chrom_lens_midpt, 
                    labels = names(chrom_lens), 
                    expand = expansion( mult = 0.02))+
  scale_y_discrete( name = "Protein coding gene",limits = chrom_lens_midpt, labels = names(chrom_lens), expand = expansion( mult = 0.02))+
  theme( axis.text = element_text(size = 10),
          panel.grid.major.x = element_blank(),
          panel.grid.major.y = element_blank()
         #legend.position = "none",
        #plot.margin = unit(c(1, 1, 1, 2), "cm")
        ) -> pqtl_plot

#ggplotly(pqtl_plot, tooltip = "text")

pqtl_plot
Figure 4A: Genetic mapping identifies 1,677 significant pQTL (LOD >7.5, permutation genome-wide p < 0.05, FDR = 0.06) where 1,056 are local (within 10Mb of the protein coding gene, seen on the diagonal) and 621 are distant (off the diagonal). pQTL are plotted across the genome where the x-axis shows the location of the pQTL and the y-axis shows the midpoint of the protein coding gene.

Figure 4A: Genetic mapping identifies 1,677 significant pQTL (LOD >7.5, permutation genome-wide p < 0.05, FDR = 0.06) where 1,056 are local (within 10Mb of the protein coding gene, seen on the diagonal) and 621 are distant (off the diagonal). pQTL are plotted across the genome where the x-axis shows the location of the pQTL and the y-axis shows the midpoint of the protein coding gene.



Data used in making the plot above can be downloaded below.

list(Figure4A_data) %>% 
    downloadthis::download_this(
    output_name = "Figure4A data",
    output_extension = ".xlsx",
    button_label = "Download Figure 4A data as xlsx",
    button_type = "primary",
    has_icon = TRUE,
    icon = "fa fa-save"
  )


Table S5: List of all significant pQTL in Diversity Outbred mESCs.

Significant pQTL (LOD > 7.5) are listed with gene annotations including Eensembl protein and gene ID, chromosome number, gene start and end coordinates (bp). In addition, QTL details include the peak chromosome and location (cM) and physical (bp) coordinates, as well as the QTL type (local or distant), QTL peaks within 10Mb of the gene midpoint are classified as local.

peaks.esc_prot_annotated %>% 
  filter( lod > 7.5) %>% 
  mutate( local = ifelse( local ==T, "Local", "Distant")) %>% 
  left_join( all.prots %>% 
               select(protein_id, mgi_symbol)
             ) %>% 
  left_join(all.genes %>% 
              select( mgi_symbol, ensembl_gene_id)
            ) %>% 
  mutate( peak_chr = as.character(peak_chr),
          gene_chr = as.character(gene_chr)) %>%  
  select(
    `Protein ID`= protein_id,
    `Gene ID` = ensembl_gene_id,
    `MGI symbol` = mgi_symbol,
    `QTL peak location (chr)` = peak_chr,
    `QTL peak location (bp)` = interp_bp_peak,
    `QTL peak location (cM)` = peak_cM,
    `QTL LOD score` = lod,
    `Protein coding gene location (chr)` = gene_chr,
    `Protein coding gene start (bp)` = gene_start,
    `Protein coding gene end (bp)` = gene_end,
    `QTL type` = local
  ) %>% 
  mutate_if(is.numeric, round ,2) -> table_s5


Example pQTL mapping code

For a single protein below is code for:

  • rankZ normalization
  • pQTL mapping
  • Finding the pQTL peak
  • Getting the allele effects at the pQTL peak

Please click on ‘code’ button below to make the code chunk visible.

# select protein example ENSMUSP00000109687, Tcf7l1
protein_example_id <- "ENSMUSP00000109687"

# 1 - rankZ normalize
rankZ <- function (x) {
  x <- rank(x, na.last = "keep", ties.method = "average")/(sum(!is.na(x)) + 1)
  qnorm(x)
}
protein_abundance <- expr.esc_prot[,"ENSMUSP00000109687", drop = FALSE]
protein_abundance_rankZ <- apply( protein_abundance, 2, rankZ)

# 2 - pQTL mapping
pQTL_scan <- qtl2::scan1(genoprobs = probs.esc_prot, 
                         pheno = protein_abundance_rankZ, 
                         kinship = kinship_loco.esc_prot, 
                         addcovar = covar.esc_prot
                         )

# 3 - get pQTL peak
pQTL_peak <- find_peaks( scan1_output = pQTL_scan, 
                         map = gmap, 
                         threshold = 5)
pQTL_peak_significant <- pQTL_peak %>% 
  filter(lod >7.5)

# 4 - get effects at the significant pQTL peak
# First interpolate the peak location from cM to bp
interp_bp <- function(df) {
  
  df <- arrange(df, peak_chr, peak_cM)
  peak_gpos <- select(df, peak_chr, peak_cM)
  chr <- peak_gpos$peak_chr
  f <- factor(chr, chroms)
  peak_gcoord_list <- split(peak_gpos$peak_cM, f)
  peak_pcoord_list <- qtl2::interp_map(peak_gcoord_list, gmap, pmap)
  df$interp_bp_peak <- unsplit(peak_pcoord_list, f)
  df
}
pQTL_peak_significant <- pQTL_peak_significant %>% 
  mutate( peak_chr = chr, peak_cM = pos) %>% 
  interp_bp(.)
# Then we need to get the bounding markers for the QTL peak
# i.e. markers on the 69k grid that are up- and downstream of the peak
query <- pQTL_peak_significant %>% 
  dplyr::select(peak_chr, interp_bp_peak) %>%
  dplyr::rename(chrom=peak_chr, start=interp_bp_peak) %>% 
  mutate(end=start) %>%
  GenomicRanges::GRanges()  
subject <- select(map_dat2, chrom, pos_bp) %>% 
  dplyr::rename(start=pos_bp) %>%
  mutate(end=start) %>% 
  GenomicRanges::GRanges()   # length 69,005
pQTL_peak_significant$before <- map_dat2$marker[follow(query, subject)]
pQTL_peak_significant$after <- map_dat2$marker[precede(query, subject)]
# Now we can get the average allele effects between the two markers
subset_probs <- function(this_probs, this_chrom, this_markers) {
    att <- attributes(this_probs)
    att$names <- this_chrom
    att$is_x_chr <- setNames(FALSE, this_chrom)
    #assert_that(all(this_markers %in% dimnames(this_probs[[this_chrom]])[[3]]))
    newprobs <- list(this_probs[[this_chrom]][, , this_markers, drop=FALSE])
    names(newprobs) <- this_chrom
    attributes(newprobs) <- att
    newprobs
}
probs_2marker <- subset_probs(probs.esc_prot, 
                              pQTL_peak_significant$peak_chr, 
                              c(pQTL_peak_significant$before, pQTL_peak_significant$after)
                              )
pQTL_effects <- scan1blup(genoprobs = probs_2marker, 
                          pheno = protein_abundance_rankZ,
                          kinship = kinship_loco.esc_prot[[pQTL_peak_significant$peak_chr]],
                          addcovar = covar.esc_prot
                          )
pQTL_effects <- colMeans(pQTL_effects[, LETTERS[1:8]]) %>%
  as_tibble()

# add effects to the peaks & add annotations
pQTL_peak_significant <- cbind(pQTL_peak_significant, t(as.matrix(pQTL_effects))) %>% 
  rename( protein_id = lodcolumn) %>% 
  left_join( all.prots) %>% 
  select(-lodindex, -chr)


# Print the results
pQTL_peak_significant



Figure 4B: Correlation of allele effects

shared.qtl <- peaks.esc.overlap.wEffs %>% 
  filter(match %in% c("shared","shared_eQTL_pQTL") & 
         !(lod.esc_rna < 7.5 & lod.esc_prot < 7.5)) %>% 
  select( ensembl_gene_id, protein_id, mgi_symbol, peak_chr, interp_bp_peak.esc_rna, interp_bp_peak.esc_prot, lod.esc_prot, lod.esc_rna) %>% 
  distinct()

shared.qtl.effects <- peaks.esc.overlap.wEffs %>%
  select( ensembl_gene_id, protein_id, mgi_symbol, peak_chr, interp_bp_peak.esc_rna, interp_bp_peak.esc_prot, lod.esc_prot, lod.esc_rna,
          paste0(LETTERS[1:8],".esc_prot"), paste0(LETTERS[1:8],".esc_rna"),
          local.esc_rna, local.esc_prot
          ) %>% 
  distinct() %>% 
  right_join(., shared.qtl) %>%
  mutate(local = ifelse((local.esc_rna == TRUE | local.esc_prot == T), "local", "distant")) %>%
  filter(!is.na(A.esc_rna), !is.na(A.esc_prot)) %>%
  mutate(qtl_id = paste0("qtl_", 1:n()))

shared.esc_rna.effs <- shared.qtl.effects %>%
  select(c(paste0(LETTERS[1:8], ".esc_rna"), "qtl_id")) %>%
  column_to_rownames("qtl_id") %>%
  t()

shared.esc_prot.effs <- shared.qtl.effects %>%
  select(c(paste0(LETTERS[1:8], ".esc_prot"), "qtl_id")) %>%
  column_to_rownames("qtl_id") %>%
  t()

shared.qtl.eff.corrs <- cbind(shared.esc_rna.effs, shared.esc_prot.effs)
colnames(shared.qtl.eff.corrs) <- c(
  paste0(colnames(shared.esc_rna.effs), "_rna"),
  paste0(colnames(shared.esc_prot.effs), "_prot")
)
cor2 <- rcorr(shared.qtl.eff.corrs, type = c("pearson"))
shared.qtl.eff.corrs.df <- data.frame(
  cor = diag(cor2$r[
    endsWith(rownames(cor2$r), "_prot"),
    endsWith(colnames(cor2$r), "_rna")
  ]),
  row = rownames(cor2$r)[endsWith(rownames(cor2$r), "_prot")],
  column = colnames(cor2$r)[endsWith(colnames(cor2$r), "_rna")],
  p_val = diag(cor2$P[
    endsWith(rownames(cor2$P), "_prot"),
    endsWith(colnames(cor2$P), "_rna")
  ]),
  n = diag(cor2$n[
    endsWith(rownames(cor2$n), "_prot"),
    endsWith(colnames(cor2$n), "_rna")
  ])
) %>%
  mutate(qtl_id = gsub("_prot", "", row)) %>%
  mutate(p_adj = p.adjust(p_val, method = "BH")) %>%
  arrange(desc(abs(cor))) %>%
  left_join(., shared.qtl.effects)

Figure4B_data <- shared.qtl.eff.corrs.df %>%
  mutate(`Significance` =  ifelse(p_adj < 0.1, "FDR < 0.1", "ns")) %>% 
  select(
    `Gene ID` = ensembl_gene_id,
    `Protein ID` = protein_id,
    `MGI symbol` = mgi_symbol,
    `Correlation between allele effects` = cor,
    Significance,
    `pQTL LOD` = lod.esc_prot, 
    `eQTL LOD` = lod.esc_rna, 
    `pQTL peak location (bp)` = interp_bp_peak.esc_prot,
    `eQTL peak location (bp)` = interp_bp_peak.esc_rna
  )
Figure4B_data %>% 
  ggplot() +
  aes(y = `Correlation between allele effects`, col = Significance, fill = Significance) +
  geom_histogram(binwidth = 0.01) +
  theme_pubclean(base_size = 18) +
  #facet_wrap(~local, scales = "free") +
  scale_color_manual(values = c("dark red","dark gray")) +
  scale_fill_manual(values = c("dark red","dark gray")) +
  ylab("Haplotype effects correlation")+
  xlab("Count")+
  ylim(-1,1)+
  theme(legend.position = "right") -> allele_eff_cor_plot

allele_eff_cor_plot
Figure 4B: Majority of co-mapping eQTL and pQTL show high agreement in haplotype effects. Histogram of pairwise Pearson correlation coefficients between inferred allele effects from eQTL and pQTL scans for each gene with a co-mapping QTL. The bars are colored by the significance of the pairwise correlation.

Figure 4B: Majority of co-mapping eQTL and pQTL show high agreement in haplotype effects. Histogram of pairwise Pearson correlation coefficients between inferred allele effects from eQTL and pQTL scans for each gene with a co-mapping QTL. The bars are colored by the significance of the pairwise correlation.

Figure4B_data %>% 
  mutate_if( is.numeric, round, 2) %>% 
  create_dt()

Correlation values used in plotting in Figure 4B



Figure 4C: Overlapping QTL examples

# BSPRY plot
bspry_qtl <- peaks.esc.overlap.wEffs %>% 
  filter( lod.esc_prot >7.5, 
          lod.esc_rna > 7.5,
          lod.esc_atac >7.5,
          mgi_symbol =="Bspry")

# get allele effects
peaks.esc.overlap.wEffs %>% 
  filter( peak_id == bspry_qtl$peak_id , 
          peak_chr == bspry_qtl$peak_chr) %>% 
  select( mgi_symbol, 
          paste0(LETTERS[1:8], ".esc_atac"),
          paste0(LETTERS[1:8], ".esc_rna"),
          paste0(LETTERS[1:8], ".esc_prot")
  ) -> bspry_effects


# get QTL scans
bspry_caqtl <- scan1(genoprobs = probs.esc_atac,
                 pheno = counts.normZ[,bspry_qtl$peak_id],
                 kinship = kinship_loco.esc_atac,
                 addcovar = covar.esc_atac)

bspry_eqtl <- scan1(genoprobs = probs.esc_rna,
                 pheno = exprZ.esc_rna[,bspry_qtl$ensembl_gene_id],
                 kinship = kinship_loco.esc_rna,
                 addcovar = covar.esc_rna)

bspry_pqtl <- scan1(genoprobs = probs.esc_prot,
                 pheno = exprZ.esc_prot[,bspry_qtl$protein_id],
                 kinship = kinship_loco.esc_prot,
                 addcovar = covar.esc_prot)

bspry_caqtl %>% 
  as.data.frame( ) %>% 
  rename( caqtl = pheno1) %>% 
  mutate( marker = dimnames(bspry_caqtl)[[1]]) %>% 
  left_join(map_dat2) %>% 
  cbind(
    bspry_eqtl %>% as.data.frame() %>% rename( eqtl = pheno1)
  ) %>% 
  cbind(
    bspry_pqtl %>% as.data.frame() %>% rename( pqtl = pheno1)
  ) -> bspry_qtl_scans

tfcp2l1_qtl <- peaks.esc.overlap.wEffs %>% 
  filter( lod.esc_prot >7.5, mgi_symbol =="Tfcp2l1", match =="shared")

# Get allele effects
peaks.esc.overlap.wEffs %>% 
  filter( peak_id == tfcp2l1_qtl$peak_id , 
          peak_chr == tfcp2l1_qtl$peak_chr) %>% 
  select( mgi_symbol, 
          paste0(LETTERS[1:8], ".esc_atac"),
          paste0(LETTERS[1:8], ".esc_rna"),
          paste0(LETTERS[1:8], ".esc_prot")
  ) -> tfcp2l1_effects

# Get QTL scans
tfcp2l1_caqtl <- scan1(genoprobs = probs.esc_atac,
                     pheno = counts.normZ[,tfcp2l1_qtl$peak_id],
                     kinship = kinship_loco.esc_atac,
                     addcovar = covar.esc_atac)

tfcp2l1_eqtl <- scan1(genoprobs = probs.esc_rna,
                    pheno = exprZ.esc_rna[,tfcp2l1_qtl$ensembl_gene_id],
                    kinship = kinship_loco.esc_rna,
                    addcovar = covar.esc_rna)

tfcp2l1_pqtl <- scan1(genoprobs = probs.esc_prot,
                    pheno = exprZ.esc_prot[,tfcp2l1_qtl$protein_id],
                    kinship = kinship_loco.esc_prot,
                    addcovar = covar.esc_prot)
tfcp2l1_caqtl %>% 
  as.data.frame( ) %>% 
  rename( caqtl = pheno1) %>% 
  mutate( marker = dimnames(tfcp2l1_caqtl)[[1]]) %>% 
  left_join(map_dat2) %>% 
  cbind(
    tfcp2l1_eqtl %>% as.data.frame() %>% rename( eqtl = pheno1)
  ) %>% 
  cbind(
    tfcp2l1_pqtl %>% as.data.frame() %>% rename( pqtl = pheno1)
  ) -> tfcp2l1_qtl_scans


# merge data
Figure_4C_data_scans <- bspry_qtl_scans %>% 
  filter( chr == 4) %>% 
  mutate( Protein = "BSPRY") %>% 
  cbind(
    all.prots2 %>% 
      filter( mgi_symbol =="Bspry") %>% 
      select( gene_start, gene_end, midpoint)
  ) %>% 
  rbind(
    tfcp2l1_qtl_scans %>% 
      filter( chr == 1) %>% 
      mutate( Protein = "TFCP2L1") %>% 
      cbind(
            all.prots2 %>% 
              filter( mgi_symbol =="Tfcp2l1") %>% 
              select( gene_start, gene_end, midpoint)
      )
    ) %>% 
  select(
    Protein, 
    marker, 
    chr, 
    pos_cM,
    pos_bp,
    caqtl,
    eqtl,
    pqtl,
    gene_start,
    gene_end, 
    midpoint
  )

Figure_4C_data_effs <- bspry_effects %>% 
  mutate( Protein = "BSPRY") %>% 
  rbind(
    tfcp2l1_effects %>% 
      mutate( Protein ="TFCP2L1")
  ) %>% 
  select( -mgi_symbol) %>% 
  pivot_longer( cols = c( paste0(LETTERS[1:8], ".esc_atac"),
          paste0(LETTERS[1:8], ".esc_rna"),
          paste0(LETTERS[1:8], ".esc_prot")), 
          names_to = c("effect"),
          values_to = "value") %>% 
  separate(effect, sep ="[.]", into = c("Strain","QTL")) %>% 
  mutate( Strain = case_when( Strain == "A" ~ "A/J",
                              Strain == "B" ~ "B6",
                              Strain == "C" ~ "129",
                              Strain == "D" ~ "NOD",
                              Strain == "E" ~ "NZO",
                              Strain == "F" ~ "CAST",
                              Strain == "G" ~ "PWK",
                              Strain == "H" ~ "WSB")) %>% 
  mutate( QTL = case_when(
    QTL == "esc_atac"~"caQTL",
    QTL == "esc_rna"~"eQTL",
    QTL == "esc_prot"~"pQTL" )
  ) 
# qtl colors
qtl.colors <- c( rna = "#228833", 
                 prot = "#4477AA", 
                 atac = "#EE6677",
                 shared = "#AA3377")

# Allele effects plot
Figure_4C_data_effs %>% 
  filter( Protein =="BSPRY") %>% 
  ggplot()+
  aes( x = Strain,
       y = value, 
       col = QTL,
       group = QTL)+
  geom_point(size = 4, show.legend = FALSE)+
  geom_line(show.legend = T, size = 1.2)+
  theme_pubclean(base_size = 18)+
  scale_color_manual( values = c(qtl.colors[["atac"]],qtl.colors[["rna"]],qtl.colors[["prot"]]), 
                      labels = c("caQTL","eQTL","pQTL"))+
  ylab("Haplotype effects")+
  xlab("")+
  ylim(-2,1.1)+
  geom_hline( yintercept = 0)+
  theme(axis.line.x = element_blank(),
        axis.title = element_text(size = 18))+
  labs(col ="QTL type")+
  coord_flip( clip ="off")+
  theme(legend.position = "none") -> bspry_haplotype_plot


# LOD plots
Figure_4C_data_scans %>% 
  filter( Protein =="BSPRY") %>% 
  pivot_longer( cols = c("caqtl","eqtl","pqtl"), names_to = "qtl_type", values_to = "lod") %>% 
  mutate( qtl_type = factor( qtl_type, levels = c("caqtl","eqtl","pqtl"))) %>% 
  ggplot()+
    aes( 
      x= pos_bp,
      y = lod,
      col = qtl_type
      )+
    geom_line( size = 1.5)+
    theme_pubclean( base_size = 18)+
  scale_color_manual( values = c(qtl.colors[["atac"]],qtl.colors[["rna"]],qtl.colors[["prot"]]), 
                      labels = c("caQTL","eQTL","pQTL"))+
  xlab(paste0("Chr ",bspry_qtl$peak_chr," location (bp)"))+
  ylab( "LOD score")+
  labs(col = "QTL type")+
  geom_segment( mapping = aes(x = gene_start, xend = gene_end), y = 0, yend = 1, col = "black", size = 2) +
  geom_text( mapping = aes( x=midpoint), y = 2, label ="Bspry", size =6, col = "black", fontface = "italic") -> bspry_lod_plot

# TFCP2L1 plot
# Allele effects plot
Figure_4C_data_effs %>% 
  filter( Protein =="TFCP2L1") %>% 
  ggplot()+
  aes( x = Strain,
       y = value, 
       col = QTL,
       group = QTL)+
  geom_point(size = 4, show.legend = FALSE)+
  geom_line(show.legend = T, size = 1.2)+
  theme_pubclean(base_size = 18)+
  scale_color_manual( values = c(qtl.colors[["atac"]],qtl.colors[["rna"]],qtl.colors[["prot"]]), 
                      labels = c("caQTL","eQTL","pQTL"))+
  ylab("Haplotype effects")+
  xlab("")+
  ylim(-2,1.1)+
  geom_hline( yintercept = 0)+
  theme(axis.line.x = element_blank(),
        axis.title = element_text(size = 18))+
  labs(col ="QTL type")+
  coord_flip( clip ="off")+
  theme(legend.position = "none")  -> tfcp2l1_haplotype_plot


# LOD plots
Figure_4C_data_scans %>% 
  filter( Protein =="TFCP2L1") %>% 
  pivot_longer( cols = c("caqtl","eqtl","pqtl"), names_to = "qtl_type", values_to = "lod") %>% 
  mutate( qtl_type = factor( qtl_type, levels = c("caqtl","eqtl","pqtl"))) %>% 
  ggplot()+
    aes( 
      x= pos_bp,
      y = lod,
      col = qtl_type
      )+
    geom_line( size = 1.5)+
    theme_pubclean( base_size = 18)+
  scale_color_manual( values = c(qtl.colors[["atac"]],qtl.colors[["rna"]],qtl.colors[["prot"]]), 
                      labels = c("caQTL","eQTL","pQTL"))+
  xlab(paste0("Chr ",tfcp2l1_qtl$peak_chr," location (bp)"))+
  ylab( "LOD score")+
  labs(col = "QTL type")+
geom_segment( mapping = aes(x = gene_start, xend = gene_end), y = 0, yend = 1, col = "black", size = 2) +
  geom_text( mapping = aes( x= midpoint), y = 2, label ="Tfcp2l1", size =6, col = "black", fontface = "italic") +
  ylim(0,15)-> tfcp2l1_lod_plot

bspry_plot <- ggarrange( bspry_lod_plot, bspry_haplotype_plot,
                         common.legend = TRUE, 
                         widths = c(0.7, 0.4))

tfcp2l1_plot <- ggarrange( tfcp2l1_lod_plot, tfcp2l1_haplotype_plot, 
                           common.legend = TRUE, 
                           widths = c(0.7, 0.4) )

figure_4C <- ggarrange( bspry_plot, tfcp2l1_plot, nrow = 2)


figure_4C
Figure 4C: Examples of significant pQTL where the influence of genetic variation is seen at all three molecular layers are shown. On the left, LOD scores obtained from genome scans using chromatin accessibility (caQTL), transcript (eQTL) and protein abundance (pQTL) of the associated gene is plotted with the protein coding gene location annotated on the x-axis. On the right, haplotype effects obtained from the caQTL, eQTL and pQTL peaks are shown.

Figure 4C: Examples of significant pQTL where the influence of genetic variation is seen at all three molecular layers are shown. On the left, LOD scores obtained from genome scans using chromatin accessibility (caQTL), transcript (eQTL) and protein abundance (pQTL) of the associated gene is plotted with the protein coding gene location annotated on the x-axis. On the right, haplotype effects obtained from the caQTL, eQTL and pQTL peaks are shown.


QTL scan and effects data used in plotting Figure 4C can be downloaded below.

 list(Figure_4C_data_scans, Figure_4C_data_effs) %>%
  downloadthis::download_this(
    output_name = "Figure4C data",
    output_extension = ".xlsx",
    button_label = "Download Figure 4C data as xlsx",
    button_type = "primary",
    has_icon = TRUE,
    icon = "fa fa-save"
  )



Figure 4D: pQTL hotspots

# Get pQTL hotspots
# prep the objects
map_dat2$chromF <- factor(map_dat2$chrom, levels = c(as.character(1:19), "X"))
chrom_markers <- select(map_dat2, chromF, n) %>%
  rename(chrom = chromF) %>%
  group_by(chrom) %>%
  summarize(start = min(n), end = max(n)) %>%
  GenomicRanges::GRanges()
windows <- unlist(GenomicRanges::slidingWindows(chrom_markers, width = 50, step = 10))
markers_bynum <- select(map_dat2, chrom, n) %>%
  dplyr::rename(start = n) %>%
  mutate(end = start) %>%
  GenomicRanges::GRanges()

distant_esc_prot <- filter(peaks.esc_prot_annotated, lod > 7.5, !is.na(local) & !(local)) %>%
  select(peak_chr, interp_bp_peak) %>%
  dplyr::rename(chrom = peak_chr, end = interp_bp_peak) %>%
  mutate(start = end) %>%
  GenomicRanges::GRanges()

distant_esc_prot_sugg <- filter(peaks.esc_prot_annotated, lod > 6, !is.na(local) & !(local)) %>%
  select(peak_chr, interp_bp_peak) %>%
  dplyr::rename(chrom = peak_chr, end = interp_bp_peak) %>%
  mutate(start = end) %>%
  GenomicRanges::GRanges()

markers <- select(map_dat2, chrom, pos_bp) %>%
  dplyr::rename(start = pos_bp) %>%
  mutate(end = start) %>%
  GenomicRanges::GRanges() # length 69,005

x <- GenomicRanges::nearest(distant_esc_prot_sugg, markers)
y <- GenomicRanges::nearest(distant_esc_prot, markers)

windows$distant_esc_prot_sugg <- GenomicRanges::countOverlaps(windows, markers_bynum[x])
windows$distant_esc_prot <- GenomicRanges::countOverlaps(windows, markers_bynum[y])
window_counts <- tibble(
  chrom = as.character(GenomicRanges::seqnames(windows)),
  start = GenomicRanges::start(windows), end = GenomicRanges::end(windows),
  distant_esc_prot = windows$distant_esc_prot,
  distant_esc_prot_sugg = windows$distant_esc_prot_sugg,
)
mm <- match(window_counts$start, map_dat2$n)
m2 <- match(window_counts$end, map_dat2$n)
window_counts$pos_cM_start <- map_dat2$pos_cM[mm]
window_counts$pos_bp_start <- map_dat2$pos_bp[mm]
window_counts$pos_cM_end <- map_dat2$pos_cM[m2]
window_counts$pos_bp_end <- map_dat2$pos_bp[m2]
window_counts <- window_counts %>%
  mutate(midpoint = (pos_cM_end + pos_cM_start) / 2, 4)

x <- select(window_counts, chrom, starts_with("pos_bp"), starts_with("distant")) %>%
  filter( distant_esc_prot > quantile(distant_esc_prot,0.995) |
          distant_esc_prot_sugg > quantile(distant_esc_prot_sugg,0.995) )

bands.esc.prot <- x %>%
  rename(start = pos_bp_start, end = pos_bp_end) %>%
  GenomicRanges::GRanges() %>%
  GenomicRanges::reduce()
# reduce collapses overlapping windows into one big window. 
bands.esc.prot$distant_esc_prot <- GenomicRanges::countOverlaps(bands.esc.prot, distant_esc_prot)
bands.esc.prot$distant_esc_prot_sugg <- GenomicRanges::countOverlaps(bands.esc.prot, distant_esc_prot_sugg)

# Plot hotspots
bands.esc.prot %>% 
  as_tibble() %>% 
  select( chrom = seqnames, start, end, distant_esc_prot) %>% 
  mutate( hotspot_midpoint = (start+end)/2 ) %>% 
  # adding all the marker locations to match axes
  rbind( (map_dat2 %>% 
              select( chrom, start = pos_bp, end =pos_bp) %>% 
              mutate( distant_esc_prot = 0,
                      hotspot_midpoint = start))) %>% 
  mutate( chrom = factor(chrom, levels = c(seq(1:19),"X")) ) -> pqtl_counts

# adding all the markers with 0 hotspot values to match the axes
pqtl_counts$midpoint_offset <- pqtl_counts$hotspot_midpoint + chrom_lens_offset[pqtl_counts$chrom]

Figure4D_data <- pqtl_counts %>% 
  select(
    Chr = chrom, 
    `Offsetted hotspot midpoint (bp)` = midpoint_offset,
    `# of distant pQTL` = distant_esc_prot
  )
# graphical prep for chromosome locations
chroms <- c(as.character(1:19), "X")
chrom_lens <- c( 195431559, 182107670, 160017104, 156496071, 151833620, 149721874, 145434693, 129399468, 124582650, 130685419, 122078650, 120120622 ,120387272, 124867725, 104015452, 98180002, 94984432, 90672596, 61417310 , 171028300)
names(chrom_lens) <- chroms
chrom_lens_offset <- cumsum(chrom_lens) - chrom_lens
chrom_lens_midpt <- chrom_lens_offset + chrom_lens / 2

Figure4D_data %>% 
  ggplot()+
  aes( x = `Offsetted hotspot midpoint (bp)`, 
       y = `# of distant pQTL`)+
  geom_bar( stat = "identity", width = 100, col =qtl.colors[["prot"]], fill= qtl.colors[["prot"]] )+
  theme_pubclean(base_size = 16)+
  scale_x_continuous( name = "Chr",
                      breaks = chrom_lens_midpt, 
                      labels = names(chrom_lens), expand = expansion(mult = .02) )+
  xlab("")+
  ylab("# of distant pQTL")+
  theme( axis.text = element_text(size = 10)) -> trans_band_plot

trans_band_plot
Figure 4D: Histogram depicting the number of total distant pQTL forming hotspots across the genome.

Figure 4D: Histogram depicting the number of total distant pQTL forming hotspots across the genome.


Data used in plotting Figure 4D can be downloaded below.

list(Figure4D_data) %>% 
  downloadthis::download_this(
    output_name = "Figure4D data",
    output_extension = ".xlsx",
    button_label = "Download Figure 4D data as xlsx",
    button_type = "primary",
    has_icon = TRUE,
    icon = "fa fa-save"
  )


Table S6: List of pQTL hotspots and their target proteins.

The details of each pQTL hotspot such as chromosomal location, start, end, width and the number of significant (LOD > 7.5) and suggestive (LOD > 6) pQTL found are listed. For each, the suggestive distant pQTL found within the hotspot is listed with gene annotations and QTL details as well.

# QTL Chromosome    QTL Start (bp)  QTL End (bp)    QTL Width (bp)  Number of Significant Distant pQTL (LOD > 7.5)  Number of Suggestive Distant pQTL (LOD > 6)
bands.esc.prot %>% 
  as_tibble() %>% 
  filter(distant_esc_prot > 20) %>% 
  select(
    `QTL Hotspot Chromosome` = seqnames,
    `QTL Hotspot Start (bp)` = start,
    `QTL Hotspot End (bp)` = end, 
    `QTL Hotspot Width (bp)` = width,
    `Number of Signfiicant Distant pQTl (LOD > 7.5)` = distant_esc_prot,
    `Number of Suggestive Distant pQTl (LOD > 6)` = distant_esc_prot_sugg
  ) -> tables6_sheet1


bands.esc.prot %>% 
  as_tibble() %>% 
  filter(distant_esc_prot > 20) -> bands_esc_prot_signif

peaks.esc_prot_annotated %>% 
  filter( peak_chr == 4) %>% 
  filter(
    local == FALSE & 
      interp_bp_peak >= bands_esc_prot_signif$start[1] &
      interp_bp_peak <= bands_esc_prot_signif$end[1]  &
      lod > 6
  ) %>% 
  select(
    `Protein ID` = protein_id, 
    `Gene ID` = ensembl_gene_id,
    `MGI Symbol` = mgi_symbol,
    `Gene Chr` = gene_chr,
    `Gene Start (bp)` = gene_start,
    `Gene End (bp)` = gene_end, 
    `QTL Chr` = peak_chr,
    `QTL Position (cM)` = peak_cM,
    `QTL Position (bp)` = interp_bp_peak, 
    `LOD Score` = lod
  ) %>% 
    mutate_if( is.numeric, round ,2)-> tables6_sheet2

peaks.esc_prot_annotated %>% 
  filter( peak_chr == 9) %>% 
  filter(
    local == FALSE & 
      interp_bp_peak >= bands_esc_prot_signif$start[2] &
      interp_bp_peak <= bands_esc_prot_signif$end[2]  &
      lod > 6
  ) %>% 
  select(
    `Protein ID` = protein_id, 
    `Gene ID` = ensembl_gene_id,
    `MGI Symbol` = mgi_symbol,
    `Gene Chr` = gene_chr,
    `Gene Start (bp)` = gene_start,
    `Gene End (bp)` = gene_end, 
    `QTL Chr` = peak_chr,
    `QTL Position (cM)` = peak_cM,
    `QTL Position (bp)` = interp_bp_peak, 
    `LOD Score` = lod
  ) %>% 
    mutate_if( is.numeric, round ,2) -> tables6_sheet3


peaks.esc_prot_annotated %>% 
  filter( peak_chr == 15) %>% 
  filter(
    local == FALSE & 
      interp_bp_peak >= bands_esc_prot_signif$start[3] &
      interp_bp_peak <= bands_esc_prot_signif$end[3]  &
      lod > 6
  ) %>% 
  select(
    `Protein ID` = protein_id, 
    `Gene ID` = ensembl_gene_id,
    `MGI Symbol` = mgi_symbol,
    `Gene Chr` = gene_chr,
    `Gene Start (bp)` = gene_start,
    `Gene End (bp)` = gene_end, 
    `QTL Chr` = peak_chr,
    `QTL Position (cM)` = peak_cM,
    `QTL Position (bp)` = interp_bp_peak, 
    `LOD Score` = lod
  ) %>% 
    mutate_if( is.numeric, round ,2) -> tables6_sheet4



Figure S4A-B: Details of the pQTL hotspot on chromosome 15

chr15.pQTL <- peaks.esc_prot.wEffs %>%
  filter(peak_chr == 15) %>%
  filter(lod.esc_prot > 6 & !local.esc_prot & !is.na(protein_id) &
    interp_bp_peak.esc_prot > filter(bands_esc_prot_signif)$start[3] &
    interp_bp_peak.esc_prot < filter(bands_esc_prot_signif)$end[3])

chr15.all.genes.weff.mat <- chr15.pQTL %>%
  filter(!is.na(A.esc_prot)) %>%
  select(c(paste0(LETTERS[1:8], ".esc_prot"), "mgi_symbol")) %>%
  distinct() %>%
  column_to_rownames("mgi_symbol") %>%
  as.matrix() %>%
  t()

annotation_row <- data.frame(strain = c("AJ", "B6", "129", "NOD", "NZO", "CAST", "PWK", "WSB"))
rownames(annotation_row) <- rownames(chr15.all.genes.weff.mat)

annot.colors <- list(
  strain = c(
   c(AJ = "#F0E442", B6 = "#555555", `129` = "#E69F00", NOD = "#0072B2",
   NZO = "#56B4E9", CAST = "#009E73", PWK = "#D55E00", WSB = "#CC79A7")
  ),
  match = c(ESC_pQTL = qtl.colors[["prot"]], shared = qtl.colors[["shared"]])
)


(pheatmap(chr15.all.genes.weff.mat,
  cluster_rows = T, show_rownames = FALSE,
  cluster_cols = T, show_colnames = FALSE,
  clustering_method = "complete",
  scale = "none",
  clustering_distance_cols = "correlation",
  clustering_distance_rows = "correlation",
  main = "Founder allele effects of suggestive pQTL within chr 15 hotspot",
  #annotation_col = annotation,
  annotation_row = annotation_row,
  annotation_colors = annot.colors, cutree_rows = 2,
  cellwidth = 3
)) 
Figure S4A: The allelic split observed in previously described eQTL hotspot on chromosome 15 is also observed for the pQTL hotspot. Heatmap showing haplotype effects at suggestive distant pQTL peaks (LOD > 6) within the chromosome 15 hotspot.

Figure S4A: The allelic split observed in previously described eQTL hotspot on chromosome 15 is also observed for the pQTL hotspot. Heatmap showing haplotype effects at suggestive distant pQTL peaks (LOD > 6) within the chromosome 15 hotspot.


pqtl_rna_meds %>%
  inner_join(select(chr15.pQTL, "target.id" = protein_id, "qtl.chr" = peak_chr)) -> chr15.rna.meds

pqtl_prot_meds %>% 
  inner_join(select(chr15.pQTL, "target.id" = protein_id, "qtl.chr" = peak_chr)) -> chr15.prot.meds

chr15.rna.meds %>%
  mutate( type = "rna") %>% 
  rbind( chr15.prot.meds %>%  mutate( type = "protein")) %>% 
  mutate(mediation.lod = ifelse(target.symbol == mediator.symbol, NA, mediation.lod)) %>%
  mutate(lod_drop = target.lod - mediation.lod) %>%
  group_by(target.symbol, type) %>%
  arrange(mediation.lod) %>%
  mutate(rank = rep(seq(1:n()))) -> chr15.meds.ranked

chr15.meds.ranked.sum <- chr15.meds.ranked %>%
  filter(rank == 1) %>% #filter(mediator.symbol =="Lifr") %>%  select(lod_drop)
  group_by(mediator.symbol, type) %>%
  summarize(n = length(target.symbol), min_drop = min(lod_drop, na.rm = T), max_drop = max(lod_drop, na.rm = T), med_drop = median(lod_drop, na.rm = T)) %>%
  arrange(desc(n))

# looking at the top!
results <- chr15.meds.ranked %>%
  ungroup() %>%
  select(mediator.symbol, target.symbol, mediation.lod, target.lod) %>%
  mutate(mediator.symbol = str_c(mediator.symbol, "_rna")) %>%
  mutate(lod_drop = target.lod - mediation.lod) %>%
  select(-mediation.lod, -target.lod) %>%
  filter((mediator.symbol %in% str_c(chr15.meds.ranked.sum$mediator.symbol[1:5], "_rna"))) %>%
  mutate(lod_drop = ifelse(lod_drop < 0, 0, lod_drop), lod_drop = ifelse(lod_drop > 6, 6, lod_drop)) %>%
  rename(target = target.symbol, LOD_diff = lod_drop)

ggplot(results, aes(y = mediator.symbol, x = target)) +
  geom_point(aes(color = LOD_diff, size = exp(LOD_diff) / 30), alpha = 0.6) +
  scale_color_gradientn(
    colors = c("white", "firebrick3", "navy"),
    values = scales::rescale(c(0, 3, 6)),
    name = "LOD\ndifference", limits = c(0, 6)
  ) +
  scale_size(breaks = 0:6, labels = as.character(0:6), range = c(0, 8)) +
  guides(size = "none") +
  theme_pubclean(base_size = 18) +
  theme(
    axis.text.y = element_text(size = 14, hjust = 1),
    axis.ticks = element_blank(),
    axis.text.x = element_text(size = 0),
    axis.title = element_text(size = 14),
    legend.text = element_text(size = 14),
    legend.title = element_text(size = 16),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background = element_blank()
  ) +
  xlab("Target pQTL")+
  ylab("Mediator") -> Figure_S4B

Figure_S4B
Figure S4B: Mediation analysis identifies Lifr transcript abundance as the best mediator for chromosome 15 pQTL hotspot. Decrease in LOD scores due to mediation is plotted for the top five mediators in the region for the suggestive distant pQTL. The points are colored and sized according to LOD difference. For 61/131 suggestive distant pQTL peaks in the region, Lifr transcript abundance leads to the largest drop in LOD when included as a covariate in the genetic mapping model.

Figure S4B: Mediation analysis identifies Lifr transcript abundance as the best mediator for chromosome 15 pQTL hotspot. Decrease in LOD scores due to mediation is plotted for the top five mediators in the region for the suggestive distant pQTL. The points are colored and sized according to LOD difference. For 61/131 suggestive distant pQTL peaks in the region, Lifr transcript abundance leads to the largest drop in LOD when included as a covariate in the genetic mapping model.


Figure S4C: QTL mapping with GSVA scores

# QTL mapping with GSVA scores
# Commented out and the results are saved to an RData file because it takes a long time to run.
gsva_results %>%
  filter( Category %in% (signif_results_tukey %>% filter( term %in% c("sex","lifr_geno"),
                                                          p.adj.signif != "ns" ))$Category ) %>%
  select(Category, sampleid, Enrichment_Score) %>%
  pivot_wider( id_cols = sampleid , names_from = Category, values_from = Enrichment_Score) %>%
  column_to_rownames("sampleid") %>%
  as.matrix() -> gsva_results_signif_mat

# rankZ
gsva_results_signif_mat_rankZ <- apply(gsva_results_signif_mat, 2,rankZ )
# 
# # qtl mapping
# gsva_qtl <- scan1( genoprobs = probs.esc_prot, 
#                    pheno = gsva_results_signif_mat_rankZ, 
#                    kinship = kinship_loco.esc_prot,
#                    addcovar = covar.esc_prot)
# save( gsva_qtl, file = here("_data","GSVA_qtl_scans.RData"))

load(here("../pQTL_website/_data/GSVA_qtl_scans.RData"))
gsva_qtl_peaks <- find_peaks( gsva_qtl, threshold = 7, gmap)
# add interp_peak_bp, before, after
gsva_qtl_peaks <- gsva_qtl_peaks %>% 
  left_join( ., goannot_wdef %>% select(lodcolumn=GOID,TERM) %>% distinct()) %>% 
  mutate( TERM = ifelse( is.na(TERM), lodcolumn, TERM)) %>% 
  mutate(phenotype=lodcolumn) %>%
  mutate( peak_chr = chr,
          peak_cM = pos) %>%
  interp_bp(.) #add bp location for peaks

# Get the bounding markers for each QTL peak
# i.e. markers on the 69k grid that are up- and downstream of the peak
query <- gsva_qtl_peaks %>% dplyr::select(peak_chr, interp_bp_peak) %>%
    dplyr::rename(chrom=peak_chr, start=interp_bp_peak) %>% mutate(end=start) %>%
    GenomicRanges::GRanges()
subject <- select(map_dat2, chrom, pos_bp) %>% dplyr::rename(start=pos_bp) %>%
    mutate(end=start) %>% GenomicRanges::GRanges()   # length 69,005

gsva_qtl_peaks$before <- map_dat2$marker[follow(query, subject)]
gsva_qtl_peaks$after <- map_dat2$marker[precede(query, subject)]

# plot Protein ADP ribosylation
ribo_scan_plot <- gsva_qtl[,"GO:0006471",drop=FALSE] %>% 
  as.data.frame() %>% 
  rownames_to_column("marker") %>% 
  left_join(map_dat2) %>% 
  filter( chr == 15) %>% 
  ggplot()+
    aes( 
      x= pos_bp,
      y = `GO:0006471`,
      )+
  geom_line( size = 1.5, col = qtl.colors[["prot"]])+
  theme_pubclean( base_size = 18)+
  xlab(paste0("Chr 15 location (bp)"))+
  ylab( "LOD score")+
  ylim(0,8)

ribo_effs <- scan1blup( genoprobs = probs.esc_prot[,15], 
                   pheno = gsva_results_signif_mat_rankZ[,"GO:0006471",drop=FALSE], 
                   kinship = kinship_loco.esc_prot[[15]],
                   addcovar = covar.esc_prot)  
ribo_qtl<- gsva_qtl_peaks %>% 
  filter( phenotype =="GO:0006471", peak_chr == 15)
ribo_effs <- colMeans(ribo_effs[c(ribo_qtl$before,ribo_qtl$after), LETTERS[1:8]])

ribo_effs %>% 
  as_tibble(rownames = "effect" ) %>% 
  mutate( type = "pQTL") %>% 
  mutate( effect = case_when( effect == "A" ~ "AJ",
                              effect == "B" ~ "B6",
                              effect == "C" ~ "129",
                              effect == "D" ~ "NOD",
                              effect == "E" ~ "NZO",
                              effect == "F" ~ "CAST",
                              effect == "G" ~ "PWK",
                              effect == "H" ~ "WSB")) %>% 
  ggplot()+
  aes( x = effect,
       y = value, 
       group = type)+
  geom_point(size = 4, show.legend = FALSE, col = qtl.colors[["prot"]])+
  geom_line(size = 1.2, show.legend = F, col = qtl.colors[["prot"]])+
  theme_pubclean(base_size = 18)+
  ylab("Haplotype effects")+
  xlab("")+
  ylim(-1,1)+
  geom_hline( yintercept = 0)+
  theme(axis.line.x = element_blank(),
        axis.title = element_text(size = 18))+
  coord_flip( clip ="off")+
  theme(legend.position = "none") -> ribo_hap_plot

ribo_qtl_plot <- ggarrange(ribo_scan_plot, ribo_hap_plot, nrow = 1, widths = c(0.7, 0.4))
ribo_qtl_plot
Figure S4C: Genetic mapping with GSVA scores of GO term Protein ADP-Ribosylation identifies a near significant QTL on chromosome 15 with similar haplotype effects to the chromosome 15 molecular QTL hotspot. On the left, genome scan showing LOD scores is plotted for chromosome 15. On the right, inferred haplotype effects at the QTL peak is plotted.

Figure S4C: Genetic mapping with GSVA scores of GO term Protein ADP-Ribosylation identifies a near significant QTL on chromosome 15 with similar haplotype effects to the chromosome 15 molecular QTL hotspot. On the left, genome scan showing LOD scores is plotted for chromosome 15. On the right, inferred haplotype effects at the QTL peak is plotted.



Figure 4E: Stoichometric buffering example

rpa_qtl <- peaks.esc.overlap.wEffs %>% 
  filter( lod.esc_prot >7.5, mgi_symbol %in% c("Rpa1","Rpa2","Rpa3"), match%in% c("esc_prot","shared"))

# Effects plot
# "A/J", "B6", "129", "NOD", "NZO", "CAST", "PWK", "WSB"
rpa_effects <- peaks.esc.overlap.wEffs %>% 
  filter( protein_id %in% rpa_qtl$protein_id , 
          peak_chr %in% rpa_qtl$peak_chr, 
          match%in% c("esc_prot","shared")) %>% 
  select( mgi_symbol, 
          paste0(LETTERS[1:8], ".esc_prot")
  ) 

rpa_effects_mat <- rpa_effects %>% 
  column_to_rownames("mgi_symbol") %>%  
  t()

Figure_4E_data_effs <- rpa_effects %>% 
  mutate( Protein= toupper(mgi_symbol)) %>% 
  pivot_longer( cols = c(paste0(LETTERS[1:8], ".esc_prot")), 
                names_to = c("effect"),
                values_to = "pQTL effect") %>% 
  separate(effect, sep ="[.]", into = c("Strain","type")) %>% 
  mutate( Strain = case_when( Strain == "A" ~ "A/J",
                              Strain == "B" ~ "B6",
                              Strain == "C" ~ "129",
                              Strain == "D" ~ "NOD",
                              Strain == "E" ~ "NZO",
                              Strain == "F" ~ "CAST",
                              Strain == "G" ~ "PWK",
                              Strain == "H" ~ "WSB")) 

# LOD plots
rpa_pqtl <- scan1(genoprobs = probs.esc_prot,
                      pheno = exprZ.esc_prot[,rpa_qtl$protein_id],
                      kinship = kinship_loco.esc_prot,
                      addcovar = covar.esc_prot)


Figure_4E_data_scans <- rpa_pqtl %>% 
  as_tibble(rownames = "marker") %>% 
  left_join(map_dat2)  %>% 
  filter( chr == rpa_qtl$peak_chr[1]) %>% 
  pivot_longer( cols = c("ENSMUSP00000012627","ENSMUSP00000099621","ENSMUSP00000000767"), names_to = "protein_id", values_to = "lod") %>% 
  left_join( select(all.prots, protein_id, mgi_symbol)) %>% 
  mutate( Protein= toupper(mgi_symbol)) %>% 
  mutate( Protein = factor( Protein, levels = c("RPA1","RPA2","RPA3"))) %>% 
  select( Protein, 
          `LOD score` = lod, 
          `Marker Position (bp)` = pos_bp)
Figure_4E_data_effs %>% 
  ggplot()+
  aes( x = Strain,
       y = `pQTL effect`, 
       group= Protein, 
       col = Protein)+
  geom_point(size = 4, show.legend = F)+
  geom_line(show.legend = T, size =1.2)+
  scale_color_manual( values = c( RColorBrewer::brewer.pal(6, "Blues")[3],
                                  RColorBrewer::brewer.pal(6, "Blues")[6],
                                  RColorBrewer::brewer.pal(6, "Blues")[4]))+
  theme_pubclean(base_size = 18)+
  ylab("Haplotype effects")+
  xlab("")+
  ylim(-1.6,1.6)+
  geom_hline( yintercept = 0)+
  theme(axis.line.x = element_blank(),
        axis.title = element_text(size = 18))+
  labs(shape = "Protein")+
   coord_flip( clip ="off")+
  theme(legend.position = "none") -> rpa_haplotype_plot


Figure_4E_data_scans %>% 
  ggplot()+
    aes( 
      x= `Marker Position (bp)`,
      y =  `LOD score`,
      col = Protein,
      )+
    geom_line( size = 1.5)+
    theme_pubclean( base_size = 18)+
  scale_color_manual( values = c( RColorBrewer::brewer.pal(6, "Blues")[3],
                                  RColorBrewer::brewer.pal(6, "Blues")[6],
                                  RColorBrewer::brewer.pal(6, "Blues")[4]))+
  xlab(paste0("Chr 6 location (bp)"))+
  ylab( "LOD score")+
  labs(col = "Protein")+
  geom_segment( x = 8255936, xend =  8259173, y = 0, yend = 1, col = "black", size = 2) +
  annotate( "text", x= 8257554, y = 2, label ="italic(Rpa3)", parse = TRUE, size =6) +
  ylim(0,20) -> rpa_lod_plot


Figure_4E <- ggarrange( rpa_lod_plot, rpa_haplotype_plot, common.legend = TRUE, widths = c(0.7, 0.4) )

Figure_4E
Figure 4E: An example of physical interaction propagating the effects of genetic variation is plotted. On the left, genome scan showing LOD scores across the genome for proteins RPA1, RPA2 and RPA3 is shown with the location of Rpa3 gene annotated on the x- axis. On the right, the inferred founder allele effects at the pQTL peak for all three genes are shown.

Figure 4E: An example of physical interaction propagating the effects of genetic variation is plotted. On the left, genome scan showing LOD scores across the genome for proteins RPA1, RPA2 and RPA3 is shown with the location of Rpa3 gene annotated on the x- axis. On the right, the inferred founder allele effects at the pQTL peak for all three genes are shown.


QTL scans and the effects used in plotting Figure 4E can be downloded below.

list(Figure_4E_data_scans, Figure_4E_data_effs) %>% 
    downloadthis::download_this(
    output_name = "Figure4E data",
    output_extension = ".xlsx",
    button_label = "Download Figure 4E data as xlsx",
    button_type = "primary",
    has_icon = TRUE,
    icon = "fa fa-save"
  )



Figure 4F: Overview of significant pQTL overlap with caQTL and eQTL

knitr::include_graphics(here("Figure4F.png"))
Figure 4F: Graphical overview of the different groups of pQTL where the genetic variation (QTL) influences one or more molecular layers. Molecular layers lacking any impact (i.e., no QTL above LOD >5 with matching haplotype effects) are depicted in gray.

Figure 4F: Graphical overview of the different groups of pQTL where the genetic variation (QTL) influences one or more molecular layers. Molecular layers lacking any impact (i.e., no QTL above LOD >5 with matching haplotype effects) are depicted in gray.


ids <- threeway.shared.samples$sampleid
names(ids) <- threeway.shared.samples$top_muga
threeway.shared.probs <- merged.probs[ind = threeway.shared.samples$top_muga]
threeway.shared.probs <- replace_ids(threeway.shared.probs, ids)
threeway.shared.kinship <- calc_kinship(threeway.shared.probs, type = "loco")
threeway.shared.covar <- merged.covar[threeway.shared.samples$top_muga, , drop = FALSE]
rownames(threeway.shared.covar ) <- threeway.shared.samples$sampleid

# # adding shared data matrices with new_symbol in the column names
shared.atac.data <- (counts.normZ[threeway.shared.samples$ATAC, threeway.shared.genes$peak_id])
colnames(shared.atac.data) <- threeway.shared.genes$new_symbol
rownames(shared.atac.data) <- threeway.shared.samples$sampleid

shared.rna.data <- (exprZ.esc_rna[threeway.shared.samples$sampleid, threeway.shared.genes$ensembl_gene_id])
colnames(shared.rna.data) <- threeway.shared.genes$new_symbol

shared.prot.data <- (exprZ.esc_prot[threeway.shared.samples$sampleid, threeway.shared.genes$protein_id])
colnames(shared.prot.data) <- threeway.shared.genes$new_symbol

# get the peaks only for shared genes
peaks.esc.overlap2 %>% 
 filter( protein_id %in% threeway.shared.genes$protein_id) -> peaks.threeway.shared.genes


# total significant pQTL for threeway shared genes
peaks.esc_prot_annotated %>%  
  filter( protein_id %in% threeway.shared.genes$protein_id, lod >7.5) -> significant_pQTL # 1589

# annotating pQTL
significant_pQTL %>% 
  select( lod.esc_prot = lod, 
          peak_chr,
          protein_id,
          local) %>% 
  inner_join( .,
              (peaks.threeway.shared.genes %>% 
                 select( lod.esc_prot,
                         peak_chr,
                         protein_id,
                         match)
                     )
  ) %>% 
  distinct() %>% 
  group_by( lod.esc_prot,peak_chr,protein_id) %>% 
  mutate( match_all = paste0(match, collapse = ", ")) %>% 
  select(-match) %>% 
  ungroup %>% 
  distinct() %>% 
  mutate( match = case_when(
    match_all == "esc_prot" ~"unique pQTL",
    match_all == "shared_eQTL_pQTL" ~"shared e/pQTL",
    match_all == "shared_caQTL_pQTL" ~"shared ca/pQTL",
    match_all %in% c("shared_eQTL_pQTL, shared",
                     "shared, shared_eQTL_pQTL",
                     "shared_eQTL_pQTL, shared, shared_caQTL_eQTL",
                     "shared_caQTL_eQTL, shared, shared_eQTL_pQTL",
                     "shared_eQTL_pQTL, shared_caQTL_eQTL, shared",
                     "shared, shared_caQTL_eQTL, shared_eQTL_pQTL",
                     "shared, shared_eQTL_pQTL, shared_caQTL_eQTL",
                     "shared_caQTL_eQTL, shared_eQTL_pQTL",
                     "shared_eQTL_pQTL, shared_caQTL_eQTL",
                     "shared, shared_caQTL_eQTL",
                     "shared_caQTL_eQTL, shared",
                     "shared"
                     )~"shared ca/e/pQTL"
  )) -> significant_pQTL_annot 

# I am adding caQTL/eQTL details, including allele effects to the significant pQTL.
significant_pQTL_annot %>% 
  rename( local.esc_prot = local) %>% 
  left_join(
    peaks.esc.overlap.wEffs %>%  
      select( 
        ensembl_gene_id, protein_id, peak_id,
        peak_chr, gene_chr,
        lod.esc_atac, lod.esc_rna, lod.esc_prot,
        local.esc_atac, local.esc_rna, local.esc_prot,
        interp_bp_peak.esc_atac, interp_bp_peak.esc_rna, interp_bp_peak.esc_prot,
        paste0(LETTERS[1:8],".esc_atac"),
        paste0(LETTERS[1:8],".esc_rna"),
        paste0(LETTERS[1:8],".esc_prot"),
        before.esc_atac, before.esc_rna, before.esc_prot,
        after.esc_atac, after.esc_rna, after.esc_prot,
        cumsum_bp.esc_atac, cumsum_bp.esc_rna, cumsum_bp.esc_prot,
        cumsum_bp_peak.esc_atac, cumsum_bp_peak.esc_rna, cumsum_bp_peak.esc_prot
        ) 
    ) %>% 
    mutate(qtl_id = paste0("qtl_", 1:n()),
         eff_stat = case_when( is.na(A.esc_rna) ~ "missing eQTL",
                               is.na(A.esc_prot) ~ "missing pQTL",
                               is.na(A.esc_atac) ~ "missing caQTL",
                               !is.na(A.esc_rna) & !is.na(A.esc_prot) & !is.na(A.esc_atac) ~ "all in") ) -> significant_pQTL_annot2

# allele effect correlations for genes with all three measurements
# let's fill in missing effects first for all.
effs.df1 <- list()
effs.df2 <- list()
effs.df3 <- list()
# pdf()
subset_probs <- function(this_probs, this_chrom, this_markers) {
  att <- attributes(this_probs)
  att$names <- this_chrom
  att$is_x_chr <- setNames(FALSE, this_chrom)
  assertthat::assert_that(all(this_markers %in% dimnames(this_probs[[this_chrom]])[[3]]))
  newprobs <- list(this_probs[[this_chrom]][, , this_markers, drop = FALSE])
  names(newprobs) <- this_chrom
  attributes(newprobs) <- att
  newprobs
}

# fill in missing effects using the protein markers for caQTL + eQTL
# so we are getting the allele effects at the pQTL peak for the missing values.
for (i in 1:length((significant_pQTL_annot2$qtl_id))) {
  #print(i)
  this_chrom <- significant_pQTL_annot2$peak_chr[i]
  gene.id <- significant_pQTL_annot2$ensembl_gene_id[i]
  peak_id <- significant_pQTL_annot2$peak_id[i]
  protein_id <- significant_pQTL_annot2$protein_id[i]
  
  if(significant_pQTL_annot2$eff_stat[i] =="all in"){
    next
  }
  if( significant_pQTL_annot2$eff_stat[i] =="missing eQTL"){
    
    this_markers <- c(significant_pQTL_annot2$before.esc_prot[i],significant_pQTL_annot2$after.esc_prot[i])
    probs_2marker <- subset_probs(threeway.shared.probs, this_chrom, this_markers)
    id <- threeway.shared.genes[ threeway.shared.genes$ensembl_gene_id == gene.id,]$new_symbol[1]
    effs_rna <- scan1blup(
      genoprobs = probs_2marker,
      pheno = (shared.rna.data[, id, drop = FALSE]),
      kinship = threeway.shared.kinship[[this_chrom]], 
      addcovar = threeway.shared.covar 
    )
    significant_pQTL_annot2[i, paste0(LETTERS[1:8], ".esc_rna") ] <- as.list(colMeans(effs_rna)[LETTERS[1:8]])
    
  }
  
  if( significant_pQTL_annot2$eff_stat[i] =="missing caQTL" & !is.na(peak_id)){
   
    this_markers <- c(significant_pQTL_annot2$before.esc_prot[i],significant_pQTL_annot2$after.esc_prot[i])
    probs_2marker <- subset_probs(threeway.shared.probs, this_chrom, this_markers)
    id <- threeway.shared.genes[ threeway.shared.genes$peak_id == peak_id,]$new_symbol[1]
    effs_atac <- scan1blup(
      genoprobs = probs_2marker,
      pheno = (shared.atac.data[, id, drop = FALSE]),
      kinship = threeway.shared.kinship[[this_chrom]], 
      addcovar = threeway.shared.covar 
    )
    significant_pQTL_annot2[i, paste0(LETTERS[1:8], ".esc_atac") ] <- as.list(colMeans(effs_atac)[LETTERS[1:8]])
  }
  
  # these are all significant pQTL so they all have effects! 
  # if( significant_pQTL_annot2$eff_stat[i] =="missing pQTL"){
  #   
  #   this_markers <- c(significant_pQTL_annot2$before.esc_rna[i],significant_pQTL_annot2$after.esc_rna[i])
  #   probs_2marker <- subset_probs(threeway.shared.probs, this_chrom, this_markers)
  #   effs_prot <- scan1blup(
  #     genoprobs = probs_2marker,
  #     pheno = (shared.prot.data[, id, drop = FALSE]),
  #     kinship = threeway.shared.kinship[[this_chrom]], addcovar = threeway.shared.covar 
  #   )
  #   significant_pQTL_annot2[i, paste0(LETTERS[1:8], ".esc_prot") ] <- as.list(colMeans(effs_prot)[LETTERS[1:8]])
  # }
  
  
}

# now let's get correlations.
significant_pQTL_annot2 %>%
  mutate(local = ifelse((local.esc_rna == TRUE | local.esc_prot == T | local.esc_atac == T), "local", "distant")) %>%
  #mutate(qtl_id = paste0("qtl_", 1:n())) %>%
  select(c(paste0(LETTERS[1:8], ".esc_rna"), "qtl_id")) %>%
  column_to_rownames("qtl_id") %>%
  t() -> shared.rna.effs

significant_pQTL_annot2 %>%
  mutate(local = ifelse((local.esc_rna == TRUE | local.esc_prot == T | local.esc_atac == T), "local", "distant")) %>%
  #mutate(qtl_id = paste0("qtl_", 1:n())) %>%
  select(c(paste0(LETTERS[1:8], ".esc_prot"), "qtl_id")) %>%
  column_to_rownames("qtl_id") %>%
  t() -> shared.prot.effs

significant_pQTL_annot2 %>%
  mutate(local = ifelse((local.esc_atac == TRUE | local.esc_rna == T | local.esc_atac == T), "local", "distant")) %>%
  #mutate(qtl_id = paste0("qtl_", 1:n())) %>%
  select(c(paste0(LETTERS[1:8], ".esc_atac"), "qtl_id")) %>%
  column_to_rownames("qtl_id") %>%
  t() -> shared.atac.effs

significant_pQTL_corrs_rna_atac <- cbind(shared.rna.effs, shared.atac.effs)
colnames(significant_pQTL_corrs_rna_atac) <- c(
  paste0(colnames(shared.rna.effs), "_rna"),
  paste0(colnames(shared.atac.effs), "_atac")
)
cor_rna_atac <- rcorr(significant_pQTL_corrs_rna_atac, type = c("pearson"))
significant_pQTL_corrs_rna_atac_df <- data.frame(
  cor = diag(cor_rna_atac$r[
    endsWith(rownames(cor_rna_atac$r), "_atac"),
    endsWith(colnames(cor_rna_atac$r), "_rna")
  ]),
  row = rownames(cor_rna_atac$r)[endsWith(rownames(cor_rna_atac$r), "_atac")],
  column = colnames(cor_rna_atac$r)[endsWith(colnames(cor_rna_atac$r), "_rna")],
  p_val = diag(cor_rna_atac$P[
    endsWith(rownames(cor_rna_atac$P), "_atac"),
    endsWith(colnames(cor_rna_atac$P), "_rna")
  ]),
  n = diag(cor_rna_atac$n[
    endsWith(rownames(cor_rna_atac$n), "_atac"),
    endsWith(colnames(cor_rna_atac$n), "_rna")
  ])
) %>% 
  mutate(qtl_id = gsub("_atac", "", row)) %>%
  #mutate(p_adj = p.adjust(p_val, "BH")) %>%
  arrange(desc(abs(cor))) %>%
  left_join(., (significant_pQTL_annot2 %>%
    mutate(local = ifelse((local.esc_rna == TRUE | local.esc_atac == T), "local", "distant")) )
    )


significant_pQTL_corrs_rna_prot <- cbind(shared.rna.effs, shared.prot.effs)
colnames(significant_pQTL_corrs_rna_prot) <- c(
  paste0(colnames(shared.rna.effs), "_rna"),
  paste0(colnames(shared.prot.effs), "_prot")
)
cor_rna_prot <- rcorr(significant_pQTL_corrs_rna_prot, type = c("pearson"))
significant_pQTL_corrs_rna_prot_df <- data.frame(
  cor = diag(cor_rna_prot$r[
    endsWith(rownames(cor_rna_prot$r), "_prot"),
    endsWith(colnames(cor_rna_prot$r), "_rna")
  ]),
  row = rownames(cor_rna_prot$r)[endsWith(rownames(cor_rna_prot$r), "_prot")],
  column = colnames(cor_rna_prot$r)[endsWith(colnames(cor_rna_prot$r), "_rna")],
  p_val = diag(cor_rna_prot$P[
    endsWith(rownames(cor_rna_prot$P), "_prot"),
    endsWith(colnames(cor_rna_prot$P), "_rna")
  ]),
  n = diag(cor_rna_prot$n[
    endsWith(rownames(cor_rna_prot$n), "_prot"),
    endsWith(colnames(cor_rna_prot$n), "_rna")
  ])
) %>%
  mutate(qtl_id = gsub("_prot", "", row)) %>%
  mutate(p_adj = p.adjust(p_val, method = "BH")) %>%
  arrange(desc(abs(cor))) %>%
  left_join(., (significant_pQTL_annot2 %>%
    mutate(local = ifelse((local.esc_rna == TRUE | local.esc_prot == T), "local", "distant")) )
    )


significant_pQTL_corrs_prot_atac <- cbind(shared.prot.effs, shared.atac.effs)
colnames(significant_pQTL_corrs_prot_atac) <- c(
  paste0(colnames(shared.prot.effs), "_prot"),
  paste0(colnames(shared.atac.effs), "_atac")
)
cor_prot_atac <- rcorr(significant_pQTL_corrs_prot_atac, type = c("pearson"))
significant_pQTL_corrs_prot_atac_df <- data.frame(
  cor = diag(cor_prot_atac$r[
    endsWith(rownames(cor_prot_atac$r), "_atac"),
    endsWith(colnames(cor_prot_atac$r), "_prot")
  ]),
  row = rownames(cor_prot_atac$r)[endsWith(rownames(cor_prot_atac$r), "_atac")],
  column = colnames(cor_prot_atac$r)[endsWith(colnames(cor_prot_atac$r), "_prot")],
  p_val = diag(cor_prot_atac$P[
    endsWith(rownames(cor_prot_atac$P), "_atac"),
    endsWith(colnames(cor_prot_atac$P), "_prot")
  ]),
  n = diag(cor_prot_atac$n[
    endsWith(rownames(cor_prot_atac$n), "_atac"),
    endsWith(colnames(cor_prot_atac$n), "_prot")
  ])
) %>%
  mutate(qtl_id = gsub("_atac", "", row)) %>%
  mutate(p_adj = p.adjust(p_val, method = "BH")) %>%
  arrange(desc(abs(cor))) %>%
  left_join(., (significant_pQTL_annot2 %>%
    mutate(local = ifelse((local.esc_prot == TRUE | local.esc_atac == T), "local", "distant")) )
    )


# let's add correlations back to the table:

significant_pQTL_annot2 %>% 
  full_join( 
     significant_pQTL_corrs_prot_atac_df %>% 
      select( cor_atac_prot = cor, qtl_id)
    ) %>% 
  full_join(
     significant_pQTL_corrs_rna_atac_df %>% 
      select( cor_atac_rna = cor, qtl_id)
  ) %>% 
  full_join(
    significant_pQTL_corrs_rna_prot_df %>% 
      select( cor_rna_prot = cor, qtl_id)
  ) ->  significant_pQTL_wcorr


# Let's save each category to individual objects and filter acc to thresholds
# all the unique pQTL with correlations. 
significant_pQTL_wcorr %>% 
  filter( match %in% c("unique pQTL")) -> uniq.pQTL.wcorr

# shared eQTL/pQTL with correlations
# note that atac-seq peak annotations will lead to repetitions, need to drop atac columns to get distinct eQTL/pQTL
significant_pQTL_wcorr %>% 
  filter( match %in% c("shared e/pQTL")) -> eQTL.pQTL.wcorr

# shared caQTL/pQTL with correlations
significant_pQTL_wcorr %>% 
  filter( match %in% c("shared ca/pQTL")) %>% 
  group_by(protein_id, peak_chr, lod.esc_prot, match) %>% 
  slice_max( abs(cor_atac_prot))  %>% # take the atac peaks with highest correlation, gets rid off NAs
  ungroup()  -> caQTL.pQTL.wcorr

# shared ca/e/pQTL
# keeping the atac-seq peak with the highest correlation only
significant_pQTL_wcorr %>% 
  filter( match %in% c("shared ca/e/pQTL") )   %>% 
  group_by(protein_id, peak_chr, lod.esc_prot, match) %>% 
  slice_max( abs(cor_atac_prot))  %>% # take the atac peaks with highest correlation, gets rid off NAs
  ungroup()  -> threeway.shared.pQTL.wcorr


# now I will update the pQTL classifications
# get unique pQTL
uniq.pQTL.wcorr %>% 
  select( protein_id, lod.esc_prot, peak_chr) %>% 
  distinct() %>% 
  rbind(
    eQTL.pQTL.wcorr %>% 
      filter( abs(cor_rna_prot) < 0.5) %>% 
      select( protein_id, peak_chr, lod.esc_prot) %>%
      distinct()
  ) %>% 
  rbind(
    caQTL.pQTL.wcorr %>% 
      filter( abs(cor_atac_prot) < 0.5) %>% 
      select( protein_id, peak_chr, lod.esc_prot) %>%
      distinct() 
  ) %>% 
  rbind(
    threeway.shared.pQTL.wcorr %>% 
      filter( abs(cor_atac_prot) < 0.5 & abs(cor_rna_prot) <0.5 ) %>% 
      select( protein_id, peak_chr, lod.esc_prot) %>%
      distinct() 
  ) %>% 
  mutate( match = "unique pQTL") -> unique_pQTL
# get shared eQTL/pQTL 
eQTL.pQTL.wcorr %>% 
  filter( abs(cor_rna_prot) >= 0.5) %>% # filter ones that moved to unique pQTL
  select( protein_id, lod.esc_prot, peak_chr) %>% 
  distinct() %>% 
  rbind( 
    threeway.shared.pQTL.wcorr %>% # move ones with abs(cor)<0.5 from shared ca/e/pQTL
      filter( abs(cor_atac_prot) < 0.5 & abs(cor_rna_prot) >= 0.5 ) %>% 
      select( protein_id, peak_chr, lod.esc_prot) %>%
      distinct() 
  ) %>% 
  mutate( match = "shared e/pQTL") -> shared_eQTL_pQTL
# get shared caQTL/pQTL 
caQTL.pQTL.wcorr %>% 
  filter( abs(cor_atac_prot) >=0.5) %>% # filter ones that moved to unique pQTL
  select( protein_id, lod.esc_prot, peak_chr) %>% 
  distinct() %>% 
  rbind(
    threeway.shared.pQTL.wcorr %>%  # move ones with abs(cor)<0.5 from shared ca/e/pQTL
      filter( abs(cor_atac_prot) >= 0.5 & abs(cor_rna_prot) < 0.5 ) %>% 
      select( protein_id, peak_chr, lod.esc_prot) %>%
      distinct() 
  ) %>% 
  mutate( match = "shared ca/pQTL") -> shared_caQTL_pQTL
# get shared ca/e/pQTL 
threeway.shared.pQTL.wcorr %>%
  filter( abs(cor_rna_prot) >= 0.5 & abs(cor_atac_prot) >= 0.5) %>%
  select(protein_id, peak_chr, lod.esc_prot) %>%
  distinct() %>% 
  mutate( match = "shared ca/e/pQTL") -> shared_pQTL
  
significant_pQTL_annot_updated <- rbind(
  shared_pQTL, 
  unique_pQTL,
  shared_caQTL_pQTL, 
  shared_eQTL_pQTL
) %>% 
  left_join( select(significant_pQTL_annot2, -match, -match_all, -eff_stat)
  ) %>% 
    full_join( 
     significant_pQTL_corrs_prot_atac_df %>% 
      select( cor_atac_prot = cor, qtl_id)
    ) %>% 
  full_join(
     significant_pQTL_corrs_rna_atac_df %>% 
      select( cor_atac_rna = cor, qtl_id)
  ) %>% 
  full_join(
    significant_pQTL_corrs_rna_prot_df %>% 
      select( cor_rna_prot = cor, qtl_id)
  ) %>% 
  left_join(
    peaks.threeway.shared.genes %>% select( protein_id,mgi_symbol, cumsum_bp_gene) %>% distinct()
  ) 
  
rbind(
  shared_pQTL, 
  unique_pQTL,
  shared_caQTL_pQTL, 
  shared_eQTL_pQTL
) %>%
  left_join( significant_pQTL_annot %>% 
               select(protein_id, peak_chr, lod.esc_prot, local )
             ) %>% 
  group_by(match) %>% # summarize(n = n_distinct(protein_id))
  count(match, local) %>%
  ungroup() %>% 
  mutate( local = ifelse( local, "local", "distant")) %>% 
  pivot_wider(
    id_cols = match,names_from = "local", values_from = "n"
  ) %>% 
  mutate( local = round(100*local/(sum(local))),
          distant = round(100*distant/(sum(distant)))
  ) %>% 
  select( `Overlap`=match , 
          `local (%)` = local, 
          `distant (%)`= distant) %>% 
  mutate(
    order = case_when( Overlap =="shared ca/e/pQTL"~1,
                       Overlap =="shared e/pQTL"~2,
                       Overlap == "unique pQTL"~3,
                       Overlap =="shared ca/pQTL"~4)
  ) %>% 
  arrange(order) %>% 
  select(-order) %>% 
  DT::datatable(.,
                extensions = 'Buttons',
                rownames = FALSE, 
                #filter="top",
                options = list(dom = 't',
                               buttons = c('copy'),
                               pageLength = 5, 
                               scrollX= TRUE
                               ))

Data used to generate Figure 4F.

LS0tCnRpdGxlOiAiR2VuZXRpYyBjaGFyYWN0ZXJpemF0aW9uIG9mIHRoZSBwbHVyaXBvdGVudCBwcm90ZW9tZSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgdG9jX2Zsb2F0OiAKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgo8c3R5bGU+CnAuY2FwdGlvbiB7CiAgZm9udC1zaXplOiAxZW07Cn0KPC9zdHlsZT4KCgpgYGB7ciBzZXR1cH0KCiMgb3B0aW9ucwpvcHRpb25zKHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKQprbml0cjo6b3B0c19rbml0JHNldChwcm9ncmVzcyA9IEZBTFNFKQoKYGBgCgo8YnI+Cjxicj4KCiMjIyBGaWd1cmUgNEE6IEdlbmV0aWMgbWFwIG9mIHRoZSBwbHVyaXBvdGVudCBwcm90ZW9tZQoKYGBge3IgRmlndXJlNEFfcHJlcH0KCiMgcHJlcHBpbmcgZGF0YQpwZWFrcy5lc2NfcHJvdF9hbm5vdGF0ZWQgPC0gcGVha3MuZXNjX3Byb3QgJT4lCiAgcmVuYW1lKCBwcm90ZWluX2lkID0gcGhlbm90eXBlKSAlPiUKICBsZWZ0X2pvaW4oYWxsLnByb3RzMikgJT4lCiAgbXV0YXRlKCBzYW1lX2Nocm9tID0gIChwZWFrX2NociA9PSBnZW5lX2NociksCiAgICAgICAgICBkaWZmID0gYWJzKG1pZHBvaW50IC0gaW50ZXJwX2JwX3BlYWspKSAlPiUKICBtdXRhdGUoIGxvY2FsID0gaWZlbHNlKCBzYW1lX2Nocm9tICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmYgPCAxMGUwNiwgVFJVRSwgRkFMU0UKICAgICkpICU+JSAKICAjIHJlbW92aW5nIHRoZSBwUVRMIGZvciB0aGUgcHJvdGVpbnMgdGhhdCBsYWNrIGFubm90YXRpb25zLgogIGZpbHRlcighaXMubmEobWdpX3N5bWJvbCkpIApwZWFrcy5lc2NfcHJvdF9hbm5vdGF0ZWQkY3Vtc3VtX2JwX3BlYWsgPC0gcGVha3MuZXNjX3Byb3RfYW5ub3RhdGVkJGludGVycF9icF9wZWFrICsgY2hyb21fbGVuc19vZmZzZXRbcGVha3MuZXNjX3Byb3RfYW5ub3RhdGVkJHBlYWtfY2hyXQoKRmlndXJlNEFfZGF0YSA8LSBwZWFrcy5lc2NfcHJvdF9hbm5vdGF0ZWQgJT4lIAogIGZpbHRlciggbG9kID4gNy41KSAlPiUgCiAgbXV0YXRlKCBsb2NhbCA9IGlmZWxzZSggbG9jYWwgPT1ULCAiTG9jYWwiLCAiRGlzdGFudCIpKSAlPiUgCiAgc2VsZWN0KAogICAgYFByb3RlaW4gSURgPSBwcm90ZWluX2lkLAogICAgYE9mZnNldHRlZCBRVEwgcGVhayBsb2NhdGlvbiAoYnApYCA9IGN1bXN1bV9icF9wZWFrLAogICAgYE9mZnNldHRlZCBnZW5lIG1pZHBvaW50IChicClgID0gY3Vtc3VtX2JwX2dlbmUsCiAgICBgUVRMIHBlYWsgKGNocilgID0gcGVha19jaHIsCiAgICBgUVRMIHBlYWsgKGJwKWAgPSBpbnRlcnBfYnBfcGVhaywKICAgIGBNR0kgc3ltYm9sYCA9IG1naV9zeW1ib2wsCiAgICBgR2VuZSBzdGFydGAgPSBnZW5lX3N0YXJ0LAogICAgYEdlbmUgZW5kYCA9IGdlbmVfZW5kLAogICAgYEdlbmUgY2hyYCA9IGdlbmVfY2hyCiAgKQoKCmBgYAoKPGJyPiAKCmBgYHtyIEZpZ3VyZTRBX3Bsb3QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5jYXA9IkZpZ3VyZSA0QTogR2VuZXRpYyBtYXBwaW5nIGlkZW50aWZpZXMgMSw2Nzcgc2lnbmlmaWNhbnQgcFFUTCAoTE9EID43LjUsIHBlcm11dGF0aW9uIGdlbm9tZS13aWRlIHAgPCAwLjA1LCBGRFIgPSAwLjA2KSB3aGVyZSAxLDA1NiBhcmUgbG9jYWwgKHdpdGhpbiAxME1iIG9mIHRoZSBwcm90ZWluIGNvZGluZyBnZW5lLCBzZWVuIG9uIHRoZSBkaWFnb25hbCkgYW5kIDYyMSBhcmUgZGlzdGFudCAob2ZmIHRoZSBkaWFnb25hbCkuIHBRVEwgYXJlIHBsb3R0ZWQgYWNyb3NzIHRoZSBnZW5vbWUgd2hlcmUgdGhlIHgtYXhpcyBzaG93cyB0aGUgbG9jYXRpb24gb2YgdGhlIHBRVEwgYW5kIHRoZSB5LWF4aXMgc2hvd3MgdGhlIG1pZHBvaW50IG9mIHRoZSBwcm90ZWluIGNvZGluZyBnZW5lLiIsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTd9CgoKIyBncmFwaGljYWwgcHJlcCBmb3IgY2hyb21vc29tZSBsb2NhdGlvbnMKY2hyb21zIDwtIGMoYXMuY2hhcmFjdGVyKDE6MTkpLCAiWCIpCmNocm9tX2xlbnMgPC0gYyggMTk1NDMxNTU5LCAxODIxMDc2NzAsIDE2MDAxNzEwNCwgMTU2NDk2MDcxLCAxNTE4MzM2MjAsIDE0OTcyMTg3NCwgMTQ1NDM0NjkzLCAxMjkzOTk0NjgsIDEyNDU4MjY1MCwgMTMwNjg1NDE5LCAxMjIwNzg2NTAsIDEyMDEyMDYyMiAsMTIwMzg3MjcyLCAxMjQ4Njc3MjUsIDEwNDAxNTQ1MiwgOTgxODAwMDIsIDk0OTg0NDMyLCA5MDY3MjU5NiwgNjE0MTczMTAgLCAxNzEwMjgzMDApCm5hbWVzKGNocm9tX2xlbnMpIDwtIGNocm9tcwpjaHJvbV9sZW5zX29mZnNldCA8LSBjdW1zdW0oY2hyb21fbGVucykgLSBjaHJvbV9sZW5zCmNocm9tX2xlbnNfbWlkcHQgPC0gY2hyb21fbGVuc19vZmZzZXQgKyBjaHJvbV9sZW5zIC8gMgoKIyBwcmVwcGluZyBjaHJvbW9zb21lIHNlZ21lbnRzIGZvciBjb2xvcmluZwpjaHJvbV9zZWdtZW50cyA8LSB0aWJibGUoIHN0YXJ0ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kID0gY2hyb21fbGVucywKICAgICAgICAgICAgICAgICAgICAgICAgICBjaHIgPSBjaHJvbXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9IGFzLmNoYXJhY3RlcihyZXAoYygwLDEpLDEwKSkpCmNocm9tX3NlZ21lbnRzJHN0YXJ0IDwtIGNocm9tX3NlZ21lbnRzJHN0YXJ0KyBjaHJvbV9sZW5zX29mZnNldFtjaHJvbV9zZWdtZW50cyRjaHJdCmNocm9tX3NlZ21lbnRzJGVuZCA8LSBjaHJvbV9zZWdtZW50cyRlbmQrIGNocm9tX2xlbnNfb2Zmc2V0W2Nocm9tX3NlZ21lbnRzJGNocl0KCiMgcXRsIGNvbG9ycwpxdGwuY29sb3JzIDwtIGMoIHJuYSA9ICIjMjI4ODMzIiwgCiAgICAgICAgICAgICAgICAgcHJvdCA9ICIjNDQ3N0FBIiwgCiAgICAgICAgICAgICAgICAgYXRhYyA9ICIjRUU2Njc3IiwKICAgICAgICAgICAgICAgICBzaGFyZWQgPSAiI0FBMzM3NyIpCgpnZ3Bsb3QoKSsKICBnZW9tX3JlY3QoIGRhdGEgPSBjaHJvbV9zZWdtZW50cywgYWVzKCB4bWluID1zdGFydCwgeG1heCA9IGVuZCwgeW1pbiA9IDAsIHltYXggPSBtYXgoZW5kKSwgZmlsbCA9IHR5cGUpLCAKICAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsIGFscGhhID0gMC4yLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJkYXJrIGdyYXkiLCJ3aGl0ZSIpKSsKICBnZW9tX3BvaW50KGRhdGEgPSBGaWd1cmU0QV9kYXRhLCAKICAgICAgICAgICAgYWVzKCB4ID0gIGBPZmZzZXR0ZWQgUVRMIHBlYWsgbG9jYXRpb24gKGJwKWAsIAogICAgICAgICAgICAgICAgIHkgPSBgT2Zmc2V0dGVkIGdlbmUgbWlkcG9pbnQgKGJwKWAsIAogICAgICAgICAgICAgICAgIHRleHQgPSBwYXN0ZTAoIkdlbmU6ICIsYE1HSSBzeW1ib2xgLCAiXG4iLCJjaHIiLCBgR2VuZSBjaHJgLCI6IixgR2VuZSBzdGFydGAsIi0iLGBHZW5lIGVuZGAsICJcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUVRMIHBvc2l0aW9uOiBjaHIiLCBgUVRMIHBlYWsgKGNocilgLCAiOiIsYFFUTCBwZWFrIChicClgKQogICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIHNpemUgPSAyLCAKICAgICAgICAgICAgY29sID1xdGwuY29sb3JzW1sicHJvdCJdXSwKICAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UgLAogICAgICAgICAgICApKwogIHRoZW1lX3B1YmNsZWFuKGJhc2Vfc2l6ZSA9IDE2KSsKICBzY2FsZV94X2Rpc2NyZXRlKCBuYW1lID0gInBRVEwiLAogICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGNocm9tX2xlbnNfbWlkcHQsIAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IG5hbWVzKGNocm9tX2xlbnMpLCAKICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24oIG11bHQgPSAwLjAyKSkrCiAgc2NhbGVfeV9kaXNjcmV0ZSggbmFtZSA9ICJQcm90ZWluIGNvZGluZyBnZW5lIixsaW1pdHMgPSBjaHJvbV9sZW5zX21pZHB0LCBsYWJlbHMgPSBuYW1lcyhjaHJvbV9sZW5zKSwgZXhwYW5kID0gZXhwYW5zaW9uKCBtdWx0ID0gMC4wMikpKwogIHRoZW1lKCBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICAjbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICNwbG90Lm1hcmdpbiA9IHVuaXQoYygxLCAxLCAxLCAyKSwgImNtIikKICAgICAgICApIC0+IHBxdGxfcGxvdAoKI2dncGxvdGx5KHBxdGxfcGxvdCwgdG9vbHRpcCA9ICJ0ZXh0IikKCnBxdGxfcGxvdAoKYGBgCgo8YnI+Cjxicj4KCkRhdGEgdXNlZCBpbiBtYWtpbmcgdGhlIHBsb3QgYWJvdmUgY2FuIGJlIGRvd25sb2FkZWQgYmVsb3cuCgpgYGB7ciBGaWd1cmVfNEFfZGF0YSwgZmlnLmNhcD0iU2lnbmlmaWNhbnQgcFFUTCBkZXRhaWxzIHBsb3R0ZWQgaW4gRmlndXJlIDRBLiIsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CgoKbGlzdChGaWd1cmU0QV9kYXRhKSAlPiUgCiAgICBkb3dubG9hZHRoaXM6OmRvd25sb2FkX3RoaXMoCiAgICBvdXRwdXRfbmFtZSA9ICJGaWd1cmU0QSBkYXRhIiwKICAgIG91dHB1dF9leHRlbnNpb24gPSAiLnhsc3giLAogICAgYnV0dG9uX2xhYmVsID0gIkRvd25sb2FkIEZpZ3VyZSA0QSBkYXRhIGFzIHhsc3giLAogICAgYnV0dG9uX3R5cGUgPSAicHJpbWFyeSIsCiAgICBoYXNfaWNvbiA9IFRSVUUsCiAgICBpY29uID0gImZhIGZhLXNhdmUiCiAgKQoKYGBgCgo8YnI+CgojIyMjIFRhYmxlIFM1OiBMaXN0IG9mIGFsbCBzaWduaWZpY2FudCBwUVRMIGluIERpdmVyc2l0eSBPdXRicmVkIG1FU0NzLgoKU2lnbmlmaWNhbnQgcFFUTCAoTE9EID4gNy41KSBhcmUgbGlzdGVkIHdpdGggZ2VuZSBhbm5vdGF0aW9ucyBpbmNsdWRpbmcgRWVuc2VtYmwgcHJvdGVpbiBhbmQgZ2VuZSBJRCwgY2hyb21vc29tZSBudW1iZXIsIGdlbmUgc3RhcnQgYW5kIGVuZCBjb29yZGluYXRlcyAoYnApLiBJbiBhZGRpdGlvbiwgUVRMIGRldGFpbHMgaW5jbHVkZSB0aGUgcGVhayBjaHJvbW9zb21lIGFuZCBsb2NhdGlvbiAoY00pIGFuZCBwaHlzaWNhbCAoYnApIGNvb3JkaW5hdGVzLCBhcyB3ZWxsIGFzIHRoZSBRVEwgdHlwZSAobG9jYWwgb3IgZGlzdGFudCksIFFUTCBwZWFrcyB3aXRoaW4gMTBNYiBvZiB0aGUgZ2VuZSBtaWRwb2ludCBhcmUgY2xhc3NpZmllZCBhcyBsb2NhbC4KCmBgYHtyIFRhYmxlX1M1X2dlbmVyYXRpb24sIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CgpwZWFrcy5lc2NfcHJvdF9hbm5vdGF0ZWQgJT4lIAogIGZpbHRlciggbG9kID4gNy41KSAlPiUgCiAgbXV0YXRlKCBsb2NhbCA9IGlmZWxzZSggbG9jYWwgPT1ULCAiTG9jYWwiLCAiRGlzdGFudCIpKSAlPiUgCiAgbGVmdF9qb2luKCBhbGwucHJvdHMgJT4lIAogICAgICAgICAgICAgICBzZWxlY3QocHJvdGVpbl9pZCwgbWdpX3N5bWJvbCkKICAgICAgICAgICAgICkgJT4lIAogIGxlZnRfam9pbihhbGwuZ2VuZXMgJT4lIAogICAgICAgICAgICAgIHNlbGVjdCggbWdpX3N5bWJvbCwgZW5zZW1ibF9nZW5lX2lkKQogICAgICAgICAgICApICU+JSAKICBtdXRhdGUoIHBlYWtfY2hyID0gYXMuY2hhcmFjdGVyKHBlYWtfY2hyKSwKICAgICAgICAgIGdlbmVfY2hyID0gYXMuY2hhcmFjdGVyKGdlbmVfY2hyKSkgJT4lICAKICBzZWxlY3QoCiAgICBgUHJvdGVpbiBJRGA9IHByb3RlaW5faWQsCiAgICBgR2VuZSBJRGAgPSBlbnNlbWJsX2dlbmVfaWQsCiAgICBgTUdJIHN5bWJvbGAgPSBtZ2lfc3ltYm9sLAogICAgYFFUTCBwZWFrIGxvY2F0aW9uIChjaHIpYCA9IHBlYWtfY2hyLAogICAgYFFUTCBwZWFrIGxvY2F0aW9uIChicClgID0gaW50ZXJwX2JwX3BlYWssCiAgICBgUVRMIHBlYWsgbG9jYXRpb24gKGNNKWAgPSBwZWFrX2NNLAogICAgYFFUTCBMT0Qgc2NvcmVgID0gbG9kLAogICAgYFByb3RlaW4gY29kaW5nIGdlbmUgbG9jYXRpb24gKGNocilgID0gZ2VuZV9jaHIsCiAgICBgUHJvdGVpbiBjb2RpbmcgZ2VuZSBzdGFydCAoYnApYCA9IGdlbmVfc3RhcnQsCiAgICBgUHJvdGVpbiBjb2RpbmcgZ2VuZSBlbmQgKGJwKWAgPSBnZW5lX2VuZCwKICAgIGBRVEwgdHlwZWAgPSBsb2NhbAogICkgJT4lIAogIG11dGF0ZV9pZihpcy5udW1lcmljLCByb3VuZCAsMikgLT4gdGFibGVfczUKCmBgYAoKYGBge3IgVGFibGVfUzUsIGVjaG8gPSBGQUxTRX0KCgojIHdyaXRleGw6OndyaXRlX3hsc3goIHRhYmxlX3M1LAojICAgICAgICAgICAgICAgICAgICAgcGF0aCA9IGhlcmUoIlRhYmxlUzVfU2lnbmlmaWNhbnRfcFFUTC54bHN4IiksCiMgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBUUlVFLAojICAgICAgICAgICAgICAgICAgICAgZm9ybWF0X2hlYWRlcnMgPSBUUlVFCiMgICAgICAgICAgICAgICAgICAgICApCgoKIyB4ZnVuOjplbWJlZF9maWxlKGhlcmUoIlRhYmxlX1M1Lnhsc3giKSkKCmRvd25sb2FkX2ZpbGUoCiAgcGF0aCA9IGhlcmUoIlRhYmxlX1M1Lnhsc3giKSwKICBvdXRwdXRfbmFtZSA9ICJUYWJsZV9TNSIsCiAgYnV0dG9uX2xhYmVsID0gIkRvd25sb2FkIFRhYmxlX1M1Lnhsc3giLAogIGJ1dHRvbl90eXBlID0gInByaW1hcnkiLAogIGhhc19pY29uID0gVFJVRSwKICBpY29uID0gImZhIGZhLXNhdmUiLAogIHNlbGZfY29udGFpbmVkID0gRkFMU0UKKQoKCmBgYAoKPGJyPgoKIyMjIEV4YW1wbGUgcFFUTCBtYXBwaW5nIGNvZGUKCkZvciBhIHNpbmdsZSBwcm90ZWluIGJlbG93IGlzIGNvZGUgZm9yOgoKLSAgIHJhbmtaIG5vcm1hbGl6YXRpb24KLSAgIHBRVEwgbWFwcGluZwotICAgRmluZGluZyB0aGUgcFFUTCBwZWFrCi0gICBHZXR0aW5nIHRoZSBhbGxlbGUgZWZmZWN0cyBhdCB0aGUgcFFUTCBwZWFrCgpQbGVhc2UgY2xpY2sgb24gJ2NvZGUnIGJ1dHRvbiBiZWxvdyB0byBtYWtlIHRoZSBjb2RlIGNodW5rIHZpc2libGUuIAoKYGBge3IgcFFUTF9leGFtcGxlX2NvZGUsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0KCiMgc2VsZWN0IHByb3RlaW4gZXhhbXBsZSBFTlNNVVNQMDAwMDAxMDk2ODcsIFRjZjdsMQpwcm90ZWluX2V4YW1wbGVfaWQgPC0gIkVOU01VU1AwMDAwMDEwOTY4NyIKCiMgMSAtIHJhbmtaIG5vcm1hbGl6ZQpyYW5rWiA8LSBmdW5jdGlvbiAoeCkgewogIHggPC0gcmFuayh4LCBuYS5sYXN0ID0gImtlZXAiLCB0aWVzLm1ldGhvZCA9ICJhdmVyYWdlIikvKHN1bSghaXMubmEoeCkpICsgMSkKICBxbm9ybSh4KQp9CnByb3RlaW5fYWJ1bmRhbmNlIDwtIGV4cHIuZXNjX3Byb3RbLCJFTlNNVVNQMDAwMDAxMDk2ODciLCBkcm9wID0gRkFMU0VdCnByb3RlaW5fYWJ1bmRhbmNlX3JhbmtaIDwtIGFwcGx5KCBwcm90ZWluX2FidW5kYW5jZSwgMiwgcmFua1opCgojIDIgLSBwUVRMIG1hcHBpbmcKcFFUTF9zY2FuIDwtIHF0bDI6OnNjYW4xKGdlbm9wcm9icyA9IHByb2JzLmVzY19wcm90LCAKICAgICAgICAgICAgICAgICAgICAgICAgIHBoZW5vID0gcHJvdGVpbl9hYnVuZGFuY2VfcmFua1osIAogICAgICAgICAgICAgICAgICAgICAgICAga2luc2hpcCA9IGtpbnNoaXBfbG9jby5lc2NfcHJvdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBhZGRjb3ZhciA9IGNvdmFyLmVzY19wcm90CiAgICAgICAgICAgICAgICAgICAgICAgICApCgojIDMgLSBnZXQgcFFUTCBwZWFrCnBRVExfcGVhayA8LSBmaW5kX3BlYWtzKCBzY2FuMV9vdXRwdXQgPSBwUVRMX3NjYW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgbWFwID0gZ21hcCwgCiAgICAgICAgICAgICAgICAgICAgICAgICB0aHJlc2hvbGQgPSA1KQpwUVRMX3BlYWtfc2lnbmlmaWNhbnQgPC0gcFFUTF9wZWFrICU+JSAKICBmaWx0ZXIobG9kID43LjUpCgojIDQgLSBnZXQgZWZmZWN0cyBhdCB0aGUgc2lnbmlmaWNhbnQgcFFUTCBwZWFrCiMgRmlyc3QgaW50ZXJwb2xhdGUgdGhlIHBlYWsgbG9jYXRpb24gZnJvbSBjTSB0byBicAppbnRlcnBfYnAgPC0gZnVuY3Rpb24oZGYpIHsKICAKICBkZiA8LSBhcnJhbmdlKGRmLCBwZWFrX2NociwgcGVha19jTSkKICBwZWFrX2dwb3MgPC0gc2VsZWN0KGRmLCBwZWFrX2NociwgcGVha19jTSkKICBjaHIgPC0gcGVha19ncG9zJHBlYWtfY2hyCiAgZiA8LSBmYWN0b3IoY2hyLCBjaHJvbXMpCiAgcGVha19nY29vcmRfbGlzdCA8LSBzcGxpdChwZWFrX2dwb3MkcGVha19jTSwgZikKICBwZWFrX3Bjb29yZF9saXN0IDwtIHF0bDI6OmludGVycF9tYXAocGVha19nY29vcmRfbGlzdCwgZ21hcCwgcG1hcCkKICBkZiRpbnRlcnBfYnBfcGVhayA8LSB1bnNwbGl0KHBlYWtfcGNvb3JkX2xpc3QsIGYpCiAgZGYKfQpwUVRMX3BlYWtfc2lnbmlmaWNhbnQgPC0gcFFUTF9wZWFrX3NpZ25pZmljYW50ICU+JSAKICBtdXRhdGUoIHBlYWtfY2hyID0gY2hyLCBwZWFrX2NNID0gcG9zKSAlPiUgCiAgaW50ZXJwX2JwKC4pCiMgVGhlbiB3ZSBuZWVkIHRvIGdldCB0aGUgYm91bmRpbmcgbWFya2VycyBmb3IgdGhlIFFUTCBwZWFrCiMgaS5lLiBtYXJrZXJzIG9uIHRoZSA2OWsgZ3JpZCB0aGF0IGFyZSB1cC0gYW5kIGRvd25zdHJlYW0gb2YgdGhlIHBlYWsKcXVlcnkgPC0gcFFUTF9wZWFrX3NpZ25pZmljYW50ICU+JSAKICBkcGx5cjo6c2VsZWN0KHBlYWtfY2hyLCBpbnRlcnBfYnBfcGVhaykgJT4lCiAgZHBseXI6OnJlbmFtZShjaHJvbT1wZWFrX2Nociwgc3RhcnQ9aW50ZXJwX2JwX3BlYWspICU+JSAKICBtdXRhdGUoZW5kPXN0YXJ0KSAlPiUKICBHZW5vbWljUmFuZ2VzOjpHUmFuZ2VzKCkgIApzdWJqZWN0IDwtIHNlbGVjdChtYXBfZGF0MiwgY2hyb20sIHBvc19icCkgJT4lIAogIGRwbHlyOjpyZW5hbWUoc3RhcnQ9cG9zX2JwKSAlPiUKICBtdXRhdGUoZW5kPXN0YXJ0KSAlPiUgCiAgR2Vub21pY1Jhbmdlczo6R1JhbmdlcygpICAgIyBsZW5ndGggNjksMDA1CnBRVExfcGVha19zaWduaWZpY2FudCRiZWZvcmUgPC0gbWFwX2RhdDIkbWFya2VyW2ZvbGxvdyhxdWVyeSwgc3ViamVjdCldCnBRVExfcGVha19zaWduaWZpY2FudCRhZnRlciA8LSBtYXBfZGF0MiRtYXJrZXJbcHJlY2VkZShxdWVyeSwgc3ViamVjdCldCiMgTm93IHdlIGNhbiBnZXQgdGhlIGF2ZXJhZ2UgYWxsZWxlIGVmZmVjdHMgYmV0d2VlbiB0aGUgdHdvIG1hcmtlcnMKc3Vic2V0X3Byb2JzIDwtIGZ1bmN0aW9uKHRoaXNfcHJvYnMsIHRoaXNfY2hyb20sIHRoaXNfbWFya2VycykgewogICAgYXR0IDwtIGF0dHJpYnV0ZXModGhpc19wcm9icykKICAgIGF0dCRuYW1lcyA8LSB0aGlzX2Nocm9tCiAgICBhdHQkaXNfeF9jaHIgPC0gc2V0TmFtZXMoRkFMU0UsIHRoaXNfY2hyb20pCiAgICAjYXNzZXJ0X3RoYXQoYWxsKHRoaXNfbWFya2VycyAlaW4lIGRpbW5hbWVzKHRoaXNfcHJvYnNbW3RoaXNfY2hyb21dXSlbWzNdXSkpCiAgICBuZXdwcm9icyA8LSBsaXN0KHRoaXNfcHJvYnNbW3RoaXNfY2hyb21dXVssICwgdGhpc19tYXJrZXJzLCBkcm9wPUZBTFNFXSkKICAgIG5hbWVzKG5ld3Byb2JzKSA8LSB0aGlzX2Nocm9tCiAgICBhdHRyaWJ1dGVzKG5ld3Byb2JzKSA8LSBhdHQKICAgIG5ld3Byb2JzCn0KcHJvYnNfMm1hcmtlciA8LSBzdWJzZXRfcHJvYnMocHJvYnMuZXNjX3Byb3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwUVRMX3BlYWtfc2lnbmlmaWNhbnQkcGVha19jaHIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKHBRVExfcGVha19zaWduaWZpY2FudCRiZWZvcmUsIHBRVExfcGVha19zaWduaWZpY2FudCRhZnRlcikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQpwUVRMX2VmZmVjdHMgPC0gc2NhbjFibHVwKGdlbm9wcm9icyA9IHByb2JzXzJtYXJrZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHBoZW5vID0gcHJvdGVpbl9hYnVuZGFuY2VfcmFua1osCiAgICAgICAgICAgICAgICAgICAgICAgICAga2luc2hpcCA9IGtpbnNoaXBfbG9jby5lc2NfcHJvdFtbcFFUTF9wZWFrX3NpZ25pZmljYW50JHBlYWtfY2hyXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkY292YXIgPSBjb3Zhci5lc2NfcHJvdAogICAgICAgICAgICAgICAgICAgICAgICAgICkKcFFUTF9lZmZlY3RzIDwtIGNvbE1lYW5zKHBRVExfZWZmZWN0c1ssIExFVFRFUlNbMTo4XV0pICU+JQogIGFzX3RpYmJsZSgpCgojIGFkZCBlZmZlY3RzIHRvIHRoZSBwZWFrcyAmIGFkZCBhbm5vdGF0aW9ucwpwUVRMX3BlYWtfc2lnbmlmaWNhbnQgPC0gY2JpbmQocFFUTF9wZWFrX3NpZ25pZmljYW50LCB0KGFzLm1hdHJpeChwUVRMX2VmZmVjdHMpKSkgJT4lIAogIHJlbmFtZSggcHJvdGVpbl9pZCA9IGxvZGNvbHVtbikgJT4lIAogIGxlZnRfam9pbiggYWxsLnByb3RzKSAlPiUgCiAgc2VsZWN0KC1sb2RpbmRleCwgLWNocikKCgojIFByaW50IHRoZSByZXN1bHRzCnBRVExfcGVha19zaWduaWZpY2FudAoKYGBgCgo8IS0tIDxicj4gLS0+Cgo8IS0tIEJlbG93IGlzIGEgemlwcGVkIFJEYXRhIGZpbGUgdGhhdCBjb250YWlucyBhbGwgdGhlIG5lY2Vzc2FyeSBvYmplY3RzIGZvciB0aGUgc3RlcHMgZGV0YWlsZWQgYWJvdmUuIC0tPgoKPCEtLSAtICAgZXhwclouZXNjX3Byb3Q6IFJhbmtaIG5vcm1hbGl6ZWQgcHJvdGVpbiBhYnVuZGFuY2UgdmFsdWVzLiAtLT4KPCEtLSAtICAgcHJvYnMuZXNjX3Byb3Q6IEdlbm90eXBlIHByb2JhYmlsaXRpZXMgYWNyb3NzIDE5MCBETyBtRVNDcy4gLS0+CjwhLS0gLSAgIGNvdmFyLmVzY19wcm90OiBDb3ZhcmlhdGUgbWF0cml4IGNvbnRhaW5pbmcgc2V4ZXMgZm9yIGVhY2ggc2FtcGxlLiAtLT4KPCEtLSAtICAga2luc2hpcF9sb2NvLmVzY19wcm90OiBLaW5zaGlwIG1hdHJpeCBnZW5lcmF0ZWQgdXNpbmcgZ2Vub3R5cGUgcHJvYmFiaWxpdGllcyBhbmQgYHF0bDI6OmNhbGNfa2luc2hpcCgpYCBmdW5jdGlvbiB3aXRoIGB0eXBlID0gImxvY28iYCBvcHRpb24uICAtLT4KPCEtLSAtICAgZ21hcCwgcG1hcCwgbWFwX2RhdDI6IEdlbmV0aWMsIHBoeXNpY2FsIGFuZCBjb21iaW5lZCBtYXBzIHVzZWQgaW4gUVRMIG1hcHBpbmcuIC0tPgo8IS0tIC0gICBhbGwucHJvdHM6IFRhYmxlIGNvbnRhaW5pbmcgYW5ub3RhdGlvbnMgZm9yIGFsbCBwcm90ZWlucy4gIC0tPgoKPCEtLSBgYGB7ciBlY2hvID0gRkFMU0V9IC0tPgoKPCEtLSAjIHNhdmUoIGV4cHJaLmVzY19wcm90LCBwcm9icy5lc2NfcHJvdCAsIGNvdmFyLmVzY19wcm90LCBraW5zaGlwX2xvY28uZXNjX3Byb3QsIGdtYXAsIHBtYXAsIG1hcF9kYXQyLCBhbGwucHJvdHMsIC0tPgo8IS0tICMgICAgICAgICBmaWxlID0gaGVyZSgiRE9fbUVTQ19wUVRMX21hcHBpbmdfb2JqZWN0cy5SRGF0YSIpKSAtLT4KCjwhLS0geGZ1bjo6ZW1iZWRfZmlsZShoZXJlKCJET19tRVNDX3BRVExfbWFwcGluZ19vYmplY3RzLnppcCIpKSAtLT4KCjwhLS0gYGBgIC0tPgoKPGJyPgo8YnI+CgojIyMgRmlndXJlIDRCOiBDb3JyZWxhdGlvbiBvZiBhbGxlbGUgZWZmZWN0cwoKYGBge3IgRmlndXJlXzRCX3ByZXB9CgpzaGFyZWQucXRsIDwtIHBlYWtzLmVzYy5vdmVybGFwLndFZmZzICU+JSAKICBmaWx0ZXIobWF0Y2ggJWluJSBjKCJzaGFyZWQiLCJzaGFyZWRfZVFUTF9wUVRMIikgJiAKICAgICAgICAgIShsb2QuZXNjX3JuYSA8IDcuNSAmIGxvZC5lc2NfcHJvdCA8IDcuNSkpICU+JSAKICBzZWxlY3QoIGVuc2VtYmxfZ2VuZV9pZCwgcHJvdGVpbl9pZCwgbWdpX3N5bWJvbCwgcGVha19jaHIsIGludGVycF9icF9wZWFrLmVzY19ybmEsIGludGVycF9icF9wZWFrLmVzY19wcm90LCBsb2QuZXNjX3Byb3QsIGxvZC5lc2Nfcm5hKSAlPiUgCiAgZGlzdGluY3QoKQoKc2hhcmVkLnF0bC5lZmZlY3RzIDwtIHBlYWtzLmVzYy5vdmVybGFwLndFZmZzICU+JQogIHNlbGVjdCggZW5zZW1ibF9nZW5lX2lkLCBwcm90ZWluX2lkLCBtZ2lfc3ltYm9sLCBwZWFrX2NociwgaW50ZXJwX2JwX3BlYWsuZXNjX3JuYSwgaW50ZXJwX2JwX3BlYWsuZXNjX3Byb3QsIGxvZC5lc2NfcHJvdCwgbG9kLmVzY19ybmEsCiAgICAgICAgICBwYXN0ZTAoTEVUVEVSU1sxOjhdLCIuZXNjX3Byb3QiKSwgcGFzdGUwKExFVFRFUlNbMTo4XSwiLmVzY19ybmEiKSwKICAgICAgICAgIGxvY2FsLmVzY19ybmEsIGxvY2FsLmVzY19wcm90CiAgICAgICAgICApICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICByaWdodF9qb2luKC4sIHNoYXJlZC5xdGwpICU+JQogIG11dGF0ZShsb2NhbCA9IGlmZWxzZSgobG9jYWwuZXNjX3JuYSA9PSBUUlVFIHwgbG9jYWwuZXNjX3Byb3QgPT0gVCksICJsb2NhbCIsICJkaXN0YW50IikpICU+JQogIGZpbHRlcighaXMubmEoQS5lc2Nfcm5hKSwgIWlzLm5hKEEuZXNjX3Byb3QpKSAlPiUKICBtdXRhdGUocXRsX2lkID0gcGFzdGUwKCJxdGxfIiwgMTpuKCkpKQoKc2hhcmVkLmVzY19ybmEuZWZmcyA8LSBzaGFyZWQucXRsLmVmZmVjdHMgJT4lCiAgc2VsZWN0KGMocGFzdGUwKExFVFRFUlNbMTo4XSwgIi5lc2Nfcm5hIiksICJxdGxfaWQiKSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJxdGxfaWQiKSAlPiUKICB0KCkKCnNoYXJlZC5lc2NfcHJvdC5lZmZzIDwtIHNoYXJlZC5xdGwuZWZmZWN0cyAlPiUKICBzZWxlY3QoYyhwYXN0ZTAoTEVUVEVSU1sxOjhdLCAiLmVzY19wcm90IiksICJxdGxfaWQiKSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJxdGxfaWQiKSAlPiUKICB0KCkKCnNoYXJlZC5xdGwuZWZmLmNvcnJzIDwtIGNiaW5kKHNoYXJlZC5lc2Nfcm5hLmVmZnMsIHNoYXJlZC5lc2NfcHJvdC5lZmZzKQpjb2xuYW1lcyhzaGFyZWQucXRsLmVmZi5jb3JycykgPC0gYygKICBwYXN0ZTAoY29sbmFtZXMoc2hhcmVkLmVzY19ybmEuZWZmcyksICJfcm5hIiksCiAgcGFzdGUwKGNvbG5hbWVzKHNoYXJlZC5lc2NfcHJvdC5lZmZzKSwgIl9wcm90IikKKQpjb3IyIDwtIHJjb3JyKHNoYXJlZC5xdGwuZWZmLmNvcnJzLCB0eXBlID0gYygicGVhcnNvbiIpKQpzaGFyZWQucXRsLmVmZi5jb3Jycy5kZiA8LSBkYXRhLmZyYW1lKAogIGNvciA9IGRpYWcoY29yMiRyWwogICAgZW5kc1dpdGgocm93bmFtZXMoY29yMiRyKSwgIl9wcm90IiksCiAgICBlbmRzV2l0aChjb2xuYW1lcyhjb3IyJHIpLCAiX3JuYSIpCiAgXSksCiAgcm93ID0gcm93bmFtZXMoY29yMiRyKVtlbmRzV2l0aChyb3duYW1lcyhjb3IyJHIpLCAiX3Byb3QiKV0sCiAgY29sdW1uID0gY29sbmFtZXMoY29yMiRyKVtlbmRzV2l0aChjb2xuYW1lcyhjb3IyJHIpLCAiX3JuYSIpXSwKICBwX3ZhbCA9IGRpYWcoY29yMiRQWwogICAgZW5kc1dpdGgocm93bmFtZXMoY29yMiRQKSwgIl9wcm90IiksCiAgICBlbmRzV2l0aChjb2xuYW1lcyhjb3IyJFApLCAiX3JuYSIpCiAgXSksCiAgbiA9IGRpYWcoY29yMiRuWwogICAgZW5kc1dpdGgocm93bmFtZXMoY29yMiRuKSwgIl9wcm90IiksCiAgICBlbmRzV2l0aChjb2xuYW1lcyhjb3IyJG4pLCAiX3JuYSIpCiAgXSkKKSAlPiUKICBtdXRhdGUocXRsX2lkID0gZ3N1YigiX3Byb3QiLCAiIiwgcm93KSkgJT4lCiAgbXV0YXRlKHBfYWRqID0gcC5hZGp1c3QocF92YWwsIG1ldGhvZCA9ICJCSCIpKSAlPiUKICBhcnJhbmdlKGRlc2MoYWJzKGNvcikpKSAlPiUKICBsZWZ0X2pvaW4oLiwgc2hhcmVkLnF0bC5lZmZlY3RzKQoKRmlndXJlNEJfZGF0YSA8LSBzaGFyZWQucXRsLmVmZi5jb3Jycy5kZiAlPiUKICBtdXRhdGUoYFNpZ25pZmljYW5jZWAgPSAgaWZlbHNlKHBfYWRqIDwgMC4xLCAiRkRSIDwgMC4xIiwgIm5zIikpICU+JSAKICBzZWxlY3QoCiAgICBgR2VuZSBJRGAgPSBlbnNlbWJsX2dlbmVfaWQsCiAgICBgUHJvdGVpbiBJRGAgPSBwcm90ZWluX2lkLAogICAgYE1HSSBzeW1ib2xgID0gbWdpX3N5bWJvbCwKICAgIGBDb3JyZWxhdGlvbiBiZXR3ZWVuIGFsbGVsZSBlZmZlY3RzYCA9IGNvciwKICAgIFNpZ25pZmljYW5jZSwKICAgIGBwUVRMIExPRGAgPSBsb2QuZXNjX3Byb3QsIAogICAgYGVRVEwgTE9EYCA9IGxvZC5lc2Nfcm5hLCAKICAgIGBwUVRMIHBlYWsgbG9jYXRpb24gKGJwKWAgPSBpbnRlcnBfYnBfcGVhay5lc2NfcHJvdCwKICAgIGBlUVRMIHBlYWsgbG9jYXRpb24gKGJwKWAgPSBpbnRlcnBfYnBfcGVhay5lc2Nfcm5hCiAgKQoKYGBgCgoKYGBge3IgRmlndXJlXzRCX3Bsb3QsIGZpZy5jYXAgPSAiRmlndXJlIDRCOiBNYWpvcml0eSBvZiBjby1tYXBwaW5nIGVRVEwgYW5kIHBRVEwgc2hvdyBoaWdoIGFncmVlbWVudCBpbiBoYXBsb3R5cGUgZWZmZWN0cy4gSGlzdG9ncmFtIG9mIHBhaXJ3aXNlIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnRzIGJldHdlZW4gaW5mZXJyZWQgYWxsZWxlIGVmZmVjdHMgZnJvbSBlUVRMIGFuZCBwUVRMIHNjYW5zIGZvciBlYWNoIGdlbmUgd2l0aCBhIGNvLW1hcHBpbmcgUVRMLiBUaGUgYmFycyBhcmUgY29sb3JlZCBieSB0aGUgc2lnbmlmaWNhbmNlIG9mIHRoZSBwYWlyd2lzZSBjb3JyZWxhdGlvbi4iLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD01fQoKCkZpZ3VyZTRCX2RhdGEgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeSA9IGBDb3JyZWxhdGlvbiBiZXR3ZWVuIGFsbGVsZSBlZmZlY3RzYCwgY29sID0gU2lnbmlmaWNhbmNlLCBmaWxsID0gU2lnbmlmaWNhbmNlKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjAxKSArCiAgdGhlbWVfcHViY2xlYW4oYmFzZV9zaXplID0gMTgpICsKICAjZmFjZXRfd3JhcCh+bG9jYWwsIHNjYWxlcyA9ICJmcmVlIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJkYXJrIHJlZCIsImRhcmsgZ3JheSIpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZGFyayByZWQiLCJkYXJrIGdyYXkiKSkgKwogIHlsYWIoIkhhcGxvdHlwZSBlZmZlY3RzIGNvcnJlbGF0aW9uIikrCiAgeGxhYigiQ291bnQiKSsKICB5bGltKC0xLDEpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpIC0+IGFsbGVsZV9lZmZfY29yX3Bsb3QKCmFsbGVsZV9lZmZfY29yX3Bsb3QKCmBgYAoKCmBgYHtyIEZpZ3VyZV80Ql9kYXRhLCBmaWcuY2FwPSJDb3JyZWxhdGlvbiB2YWx1ZXMgdXNlZCBpbiBwbG90dGluZyBpbiBGaWd1cmUgNEIiLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQoKRmlndXJlNEJfZGF0YSAlPiUgCiAgbXV0YXRlX2lmKCBpcy5udW1lcmljLCByb3VuZCwgMikgJT4lIAogIGNyZWF0ZV9kdCgpCgpgYGAKCgo8YnI+Cjxicj4KCiMjIyBGaWd1cmUgNEM6IE92ZXJsYXBwaW5nIFFUTCBleGFtcGxlcwoKYGBge3IgRmlndXJlXzRDX3ByZXB9CgoKIyBCU1BSWSBwbG90CmJzcHJ5X3F0bCA8LSBwZWFrcy5lc2Mub3ZlcmxhcC53RWZmcyAlPiUgCiAgZmlsdGVyKCBsb2QuZXNjX3Byb3QgPjcuNSwgCiAgICAgICAgICBsb2QuZXNjX3JuYSA+IDcuNSwKICAgICAgICAgIGxvZC5lc2NfYXRhYyA+Ny41LAogICAgICAgICAgbWdpX3N5bWJvbCA9PSJCc3ByeSIpCgojIGdldCBhbGxlbGUgZWZmZWN0cwpwZWFrcy5lc2Mub3ZlcmxhcC53RWZmcyAlPiUgCiAgZmlsdGVyKCBwZWFrX2lkID09IGJzcHJ5X3F0bCRwZWFrX2lkICwgCiAgICAgICAgICBwZWFrX2NociA9PSBic3ByeV9xdGwkcGVha19jaHIpICU+JSAKICBzZWxlY3QoIG1naV9zeW1ib2wsIAogICAgICAgICAgcGFzdGUwKExFVFRFUlNbMTo4XSwgIi5lc2NfYXRhYyIpLAogICAgICAgICAgcGFzdGUwKExFVFRFUlNbMTo4XSwgIi5lc2Nfcm5hIiksCiAgICAgICAgICBwYXN0ZTAoTEVUVEVSU1sxOjhdLCAiLmVzY19wcm90IikKICApIC0+IGJzcHJ5X2VmZmVjdHMKCgojIGdldCBRVEwgc2NhbnMKYnNwcnlfY2FxdGwgPC0gc2NhbjEoZ2Vub3Byb2JzID0gcHJvYnMuZXNjX2F0YWMsCiAgICAgICAgICAgICAgICAgcGhlbm8gPSBjb3VudHMubm9ybVpbLGJzcHJ5X3F0bCRwZWFrX2lkXSwKICAgICAgICAgICAgICAgICBraW5zaGlwID0ga2luc2hpcF9sb2NvLmVzY19hdGFjLAogICAgICAgICAgICAgICAgIGFkZGNvdmFyID0gY292YXIuZXNjX2F0YWMpCgpic3ByeV9lcXRsIDwtIHNjYW4xKGdlbm9wcm9icyA9IHByb2JzLmVzY19ybmEsCiAgICAgICAgICAgICAgICAgcGhlbm8gPSBleHByWi5lc2Nfcm5hWyxic3ByeV9xdGwkZW5zZW1ibF9nZW5lX2lkXSwKICAgICAgICAgICAgICAgICBraW5zaGlwID0ga2luc2hpcF9sb2NvLmVzY19ybmEsCiAgICAgICAgICAgICAgICAgYWRkY292YXIgPSBjb3Zhci5lc2Nfcm5hKQoKYnNwcnlfcHF0bCA8LSBzY2FuMShnZW5vcHJvYnMgPSBwcm9icy5lc2NfcHJvdCwKICAgICAgICAgICAgICAgICBwaGVubyA9IGV4cHJaLmVzY19wcm90Wyxic3ByeV9xdGwkcHJvdGVpbl9pZF0sCiAgICAgICAgICAgICAgICAga2luc2hpcCA9IGtpbnNoaXBfbG9jby5lc2NfcHJvdCwKICAgICAgICAgICAgICAgICBhZGRjb3ZhciA9IGNvdmFyLmVzY19wcm90KQoKYnNwcnlfY2FxdGwgJT4lIAogIGFzLmRhdGEuZnJhbWUoICkgJT4lIAogIHJlbmFtZSggY2FxdGwgPSBwaGVubzEpICU+JSAKICBtdXRhdGUoIG1hcmtlciA9IGRpbW5hbWVzKGJzcHJ5X2NhcXRsKVtbMV1dKSAlPiUgCiAgbGVmdF9qb2luKG1hcF9kYXQyKSAlPiUgCiAgY2JpbmQoCiAgICBic3ByeV9lcXRsICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIHJlbmFtZSggZXF0bCA9IHBoZW5vMSkKICApICU+JSAKICBjYmluZCgKICAgIGJzcHJ5X3BxdGwgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgcmVuYW1lKCBwcXRsID0gcGhlbm8xKQogICkgLT4gYnNwcnlfcXRsX3NjYW5zCgp0ZmNwMmwxX3F0bCA8LSBwZWFrcy5lc2Mub3ZlcmxhcC53RWZmcyAlPiUgCiAgZmlsdGVyKCBsb2QuZXNjX3Byb3QgPjcuNSwgbWdpX3N5bWJvbCA9PSJUZmNwMmwxIiwgbWF0Y2ggPT0ic2hhcmVkIikKCiMgR2V0IGFsbGVsZSBlZmZlY3RzCnBlYWtzLmVzYy5vdmVybGFwLndFZmZzICU+JSAKICBmaWx0ZXIoIHBlYWtfaWQgPT0gdGZjcDJsMV9xdGwkcGVha19pZCAsIAogICAgICAgICAgcGVha19jaHIgPT0gdGZjcDJsMV9xdGwkcGVha19jaHIpICU+JSAKICBzZWxlY3QoIG1naV9zeW1ib2wsIAogICAgICAgICAgcGFzdGUwKExFVFRFUlNbMTo4XSwgIi5lc2NfYXRhYyIpLAogICAgICAgICAgcGFzdGUwKExFVFRFUlNbMTo4XSwgIi5lc2Nfcm5hIiksCiAgICAgICAgICBwYXN0ZTAoTEVUVEVSU1sxOjhdLCAiLmVzY19wcm90IikKICApIC0+IHRmY3AybDFfZWZmZWN0cwoKIyBHZXQgUVRMIHNjYW5zCnRmY3AybDFfY2FxdGwgPC0gc2NhbjEoZ2Vub3Byb2JzID0gcHJvYnMuZXNjX2F0YWMsCiAgICAgICAgICAgICAgICAgICAgIHBoZW5vID0gY291bnRzLm5vcm1aWyx0ZmNwMmwxX3F0bCRwZWFrX2lkXSwKICAgICAgICAgICAgICAgICAgICAga2luc2hpcCA9IGtpbnNoaXBfbG9jby5lc2NfYXRhYywKICAgICAgICAgICAgICAgICAgICAgYWRkY292YXIgPSBjb3Zhci5lc2NfYXRhYykKCnRmY3AybDFfZXF0bCA8LSBzY2FuMShnZW5vcHJvYnMgPSBwcm9icy5lc2Nfcm5hLAogICAgICAgICAgICAgICAgICAgIHBoZW5vID0gZXhwclouZXNjX3JuYVssdGZjcDJsMV9xdGwkZW5zZW1ibF9nZW5lX2lkXSwKICAgICAgICAgICAgICAgICAgICBraW5zaGlwID0ga2luc2hpcF9sb2NvLmVzY19ybmEsCiAgICAgICAgICAgICAgICAgICAgYWRkY292YXIgPSBjb3Zhci5lc2Nfcm5hKQoKdGZjcDJsMV9wcXRsIDwtIHNjYW4xKGdlbm9wcm9icyA9IHByb2JzLmVzY19wcm90LAogICAgICAgICAgICAgICAgICAgIHBoZW5vID0gZXhwclouZXNjX3Byb3RbLHRmY3AybDFfcXRsJHByb3RlaW5faWRdLAogICAgICAgICAgICAgICAgICAgIGtpbnNoaXAgPSBraW5zaGlwX2xvY28uZXNjX3Byb3QsCiAgICAgICAgICAgICAgICAgICAgYWRkY292YXIgPSBjb3Zhci5lc2NfcHJvdCkKdGZjcDJsMV9jYXF0bCAlPiUgCiAgYXMuZGF0YS5mcmFtZSggKSAlPiUgCiAgcmVuYW1lKCBjYXF0bCA9IHBoZW5vMSkgJT4lIAogIG11dGF0ZSggbWFya2VyID0gZGltbmFtZXModGZjcDJsMV9jYXF0bClbWzFdXSkgJT4lIAogIGxlZnRfam9pbihtYXBfZGF0MikgJT4lIAogIGNiaW5kKAogICAgdGZjcDJsMV9lcXRsICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIHJlbmFtZSggZXF0bCA9IHBoZW5vMSkKICApICU+JSAKICBjYmluZCgKICAgIHRmY3AybDFfcHF0bCAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSByZW5hbWUoIHBxdGwgPSBwaGVubzEpCiAgKSAtPiB0ZmNwMmwxX3F0bF9zY2FucwoKCiMgbWVyZ2UgZGF0YQpGaWd1cmVfNENfZGF0YV9zY2FucyA8LSBic3ByeV9xdGxfc2NhbnMgJT4lIAogIGZpbHRlciggY2hyID09IDQpICU+JSAKICBtdXRhdGUoIFByb3RlaW4gPSAiQlNQUlkiKSAlPiUgCiAgY2JpbmQoCiAgICBhbGwucHJvdHMyICU+JSAKICAgICAgZmlsdGVyKCBtZ2lfc3ltYm9sID09IkJzcHJ5IikgJT4lIAogICAgICBzZWxlY3QoIGdlbmVfc3RhcnQsIGdlbmVfZW5kLCBtaWRwb2ludCkKICApICU+JSAKICByYmluZCgKICAgIHRmY3AybDFfcXRsX3NjYW5zICU+JSAKICAgICAgZmlsdGVyKCBjaHIgPT0gMSkgJT4lIAogICAgICBtdXRhdGUoIFByb3RlaW4gPSAiVEZDUDJMMSIpICU+JSAKICAgICAgY2JpbmQoCiAgICAgICAgICAgIGFsbC5wcm90czIgJT4lIAogICAgICAgICAgICAgIGZpbHRlciggbWdpX3N5bWJvbCA9PSJUZmNwMmwxIikgJT4lIAogICAgICAgICAgICAgIHNlbGVjdCggZ2VuZV9zdGFydCwgZ2VuZV9lbmQsIG1pZHBvaW50KQogICAgICApCiAgICApICU+JSAKICBzZWxlY3QoCiAgICBQcm90ZWluLCAKICAgIG1hcmtlciwgCiAgICBjaHIsIAogICAgcG9zX2NNLAogICAgcG9zX2JwLAogICAgY2FxdGwsCiAgICBlcXRsLAogICAgcHF0bCwKICAgIGdlbmVfc3RhcnQsCiAgICBnZW5lX2VuZCwgCiAgICBtaWRwb2ludAogICkKCkZpZ3VyZV80Q19kYXRhX2VmZnMgPC0gYnNwcnlfZWZmZWN0cyAlPiUgCiAgbXV0YXRlKCBQcm90ZWluID0gIkJTUFJZIikgJT4lIAogIHJiaW5kKAogICAgdGZjcDJsMV9lZmZlY3RzICU+JSAKICAgICAgbXV0YXRlKCBQcm90ZWluID0iVEZDUDJMMSIpCiAgKSAlPiUgCiAgc2VsZWN0KCAtbWdpX3N5bWJvbCkgJT4lIAogIHBpdm90X2xvbmdlciggY29scyA9IGMoIHBhc3RlMChMRVRURVJTWzE6OF0sICIuZXNjX2F0YWMiKSwKICAgICAgICAgIHBhc3RlMChMRVRURVJTWzE6OF0sICIuZXNjX3JuYSIpLAogICAgICAgICAgcGFzdGUwKExFVFRFUlNbMTo4XSwgIi5lc2NfcHJvdCIpKSwgCiAgICAgICAgICBuYW1lc190byA9IGMoImVmZmVjdCIpLAogICAgICAgICAgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIAogIHNlcGFyYXRlKGVmZmVjdCwgc2VwID0iWy5dIiwgaW50byA9IGMoIlN0cmFpbiIsIlFUTCIpKSAlPiUgCiAgbXV0YXRlKCBTdHJhaW4gPSBjYXNlX3doZW4oIFN0cmFpbiA9PSAiQSIgfiAiQS9KIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RyYWluID09ICJCIiB+ICJCNiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0cmFpbiA9PSAiQyIgfiAiMTI5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RyYWluID09ICJEIiB+ICJOT0QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdHJhaW4gPT0gIkUiIH4gIk5aTyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0cmFpbiA9PSAiRiIgfiAiQ0FTVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0cmFpbiA9PSAiRyIgfiAiUFdLIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RyYWluID09ICJIIiB+ICJXU0IiKSkgJT4lIAogIG11dGF0ZSggUVRMID0gY2FzZV93aGVuKAogICAgUVRMID09ICJlc2NfYXRhYyJ+ImNhUVRMIiwKICAgIFFUTCA9PSAiZXNjX3JuYSJ+ImVRVEwiLAogICAgUVRMID09ICJlc2NfcHJvdCJ+InBRVEwiICkKICApIAoKYGBgCgoKYGBge3IgRmlndXJlXzRDX3Bsb3QsIGZpZy5jYXAgPSAiRmlndXJlIDRDOiBFeGFtcGxlcyBvZiBzaWduaWZpY2FudCBwUVRMIHdoZXJlIHRoZSBpbmZsdWVuY2Ugb2YgZ2VuZXRpYyB2YXJpYXRpb24gaXMgc2VlbiBhdCBhbGwgdGhyZWUgbW9sZWN1bGFyIGxheWVycyBhcmUgc2hvd24uIE9uIHRoZSBsZWZ0LCBMT0Qgc2NvcmVzIG9idGFpbmVkIGZyb20gZ2Vub21lIHNjYW5zIHVzaW5nIGNocm9tYXRpbiBhY2Nlc3NpYmlsaXR5IChjYVFUTCksIHRyYW5zY3JpcHQgKGVRVEwpIGFuZCBwcm90ZWluIGFidW5kYW5jZSAocFFUTCkgb2YgdGhlIGFzc29jaWF0ZWQgZ2VuZSBpcyBwbG90dGVkIHdpdGggdGhlIHByb3RlaW4gY29kaW5nIGdlbmUgbG9jYXRpb24gYW5ub3RhdGVkIG9uIHRoZSB4LWF4aXMuIE9uIHRoZSByaWdodCwgaGFwbG90eXBlIGVmZmVjdHMgb2J0YWluZWQgZnJvbSB0aGUgY2FRVEwsIGVRVEwgYW5kIHBRVEwgcGVha3MgYXJlIHNob3duLiIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMn0KCiMgcXRsIGNvbG9ycwpxdGwuY29sb3JzIDwtIGMoIHJuYSA9ICIjMjI4ODMzIiwgCiAgICAgICAgICAgICAgICAgcHJvdCA9ICIjNDQ3N0FBIiwgCiAgICAgICAgICAgICAgICAgYXRhYyA9ICIjRUU2Njc3IiwKICAgICAgICAgICAgICAgICBzaGFyZWQgPSAiI0FBMzM3NyIpCgojIEFsbGVsZSBlZmZlY3RzIHBsb3QKRmlndXJlXzRDX2RhdGFfZWZmcyAlPiUgCiAgZmlsdGVyKCBQcm90ZWluID09IkJTUFJZIikgJT4lIAogIGdncGxvdCgpKwogIGFlcyggeCA9IFN0cmFpbiwKICAgICAgIHkgPSB2YWx1ZSwgCiAgICAgICBjb2wgPSBRVEwsCiAgICAgICBncm91cCA9IFFUTCkrCiAgZ2VvbV9wb2ludChzaXplID0gNCwgc2hvdy5sZWdlbmQgPSBGQUxTRSkrCiAgZ2VvbV9saW5lKHNob3cubGVnZW5kID0gVCwgc2l6ZSA9IDEuMikrCiAgdGhlbWVfcHViY2xlYW4oYmFzZV9zaXplID0gMTgpKwogIHNjYWxlX2NvbG9yX21hbnVhbCggdmFsdWVzID0gYyhxdGwuY29sb3JzW1siYXRhYyJdXSxxdGwuY29sb3JzW1sicm5hIl1dLHF0bC5jb2xvcnNbWyJwcm90Il1dKSwgCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJjYVFUTCIsImVRVEwiLCJwUVRMIikpKwogIHlsYWIoIkhhcGxvdHlwZSBlZmZlY3RzIikrCiAgeGxhYigiIikrCiAgeWxpbSgtMiwxLjEpKwogIGdlb21faGxpbmUoIHlpbnRlcmNlcHQgPSAwKSsKICB0aGVtZShheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpKwogIGxhYnMoY29sID0iUVRMIHR5cGUiKSsKICBjb29yZF9mbGlwKCBjbGlwID0ib2ZmIikrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAtPiBic3ByeV9oYXBsb3R5cGVfcGxvdAoKCiMgTE9EIHBsb3RzCkZpZ3VyZV80Q19kYXRhX3NjYW5zICU+JSAKICBmaWx0ZXIoIFByb3RlaW4gPT0iQlNQUlkiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKCBjb2xzID0gYygiY2FxdGwiLCJlcXRsIiwicHF0bCIpLCBuYW1lc190byA9ICJxdGxfdHlwZSIsIHZhbHVlc190byA9ICJsb2QiKSAlPiUgCiAgbXV0YXRlKCBxdGxfdHlwZSA9IGZhY3RvciggcXRsX3R5cGUsIGxldmVscyA9IGMoImNhcXRsIiwiZXF0bCIsInBxdGwiKSkpICU+JSAKICBnZ3Bsb3QoKSsKICAgIGFlcyggCiAgICAgIHg9IHBvc19icCwKICAgICAgeSA9IGxvZCwKICAgICAgY29sID0gcXRsX3R5cGUKICAgICAgKSsKICAgIGdlb21fbGluZSggc2l6ZSA9IDEuNSkrCiAgICB0aGVtZV9wdWJjbGVhbiggYmFzZV9zaXplID0gMTgpKwogIHNjYWxlX2NvbG9yX21hbnVhbCggdmFsdWVzID0gYyhxdGwuY29sb3JzW1siYXRhYyJdXSxxdGwuY29sb3JzW1sicm5hIl1dLHF0bC5jb2xvcnNbWyJwcm90Il1dKSwgCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJjYVFUTCIsImVRVEwiLCJwUVRMIikpKwogIHhsYWIocGFzdGUwKCJDaHIgIixic3ByeV9xdGwkcGVha19jaHIsIiBsb2NhdGlvbiAoYnApIikpKwogIHlsYWIoICJMT0Qgc2NvcmUiKSsKICBsYWJzKGNvbCA9ICJRVEwgdHlwZSIpKwogIGdlb21fc2VnbWVudCggbWFwcGluZyA9IGFlcyh4ID0gZ2VuZV9zdGFydCwgeGVuZCA9IGdlbmVfZW5kKSwgeSA9IDAsIHllbmQgPSAxLCBjb2wgPSAiYmxhY2siLCBzaXplID0gMikgKwogIGdlb21fdGV4dCggbWFwcGluZyA9IGFlcyggeD1taWRwb2ludCksIHkgPSAyLCBsYWJlbCA9IkJzcHJ5Iiwgc2l6ZSA9NiwgY29sID0gImJsYWNrIiwgZm9udGZhY2UgPSAiaXRhbGljIikgLT4gYnNwcnlfbG9kX3Bsb3QKCiMgVEZDUDJMMSBwbG90CiMgQWxsZWxlIGVmZmVjdHMgcGxvdApGaWd1cmVfNENfZGF0YV9lZmZzICU+JSAKICBmaWx0ZXIoIFByb3RlaW4gPT0iVEZDUDJMMSIpICU+JSAKICBnZ3Bsb3QoKSsKICBhZXMoIHggPSBTdHJhaW4sCiAgICAgICB5ID0gdmFsdWUsIAogICAgICAgY29sID0gUVRMLAogICAgICAgZ3JvdXAgPSBRVEwpKwogIGdlb21fcG9pbnQoc2l6ZSA9IDQsIHNob3cubGVnZW5kID0gRkFMU0UpKwogIGdlb21fbGluZShzaG93LmxlZ2VuZCA9IFQsIHNpemUgPSAxLjIpKwogIHRoZW1lX3B1YmNsZWFuKGJhc2Vfc2l6ZSA9IDE4KSsKICBzY2FsZV9jb2xvcl9tYW51YWwoIHZhbHVlcyA9IGMocXRsLmNvbG9yc1tbImF0YWMiXV0scXRsLmNvbG9yc1tbInJuYSJdXSxxdGwuY29sb3JzW1sicHJvdCJdXSksIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiY2FRVEwiLCJlUVRMIiwicFFUTCIpKSsKICB5bGFiKCJIYXBsb3R5cGUgZWZmZWN0cyIpKwogIHhsYWIoIiIpKwogIHlsaW0oLTIsMS4xKSsKICBnZW9tX2hsaW5lKCB5aW50ZXJjZXB0ID0gMCkrCiAgdGhlbWUoYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKSsKICBsYWJzKGNvbCA9IlFUTCB0eXBlIikrCiAgY29vcmRfZmxpcCggY2xpcCA9Im9mZiIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgIC0+IHRmY3AybDFfaGFwbG90eXBlX3Bsb3QKCgojIExPRCBwbG90cwpGaWd1cmVfNENfZGF0YV9zY2FucyAlPiUgCiAgZmlsdGVyKCBQcm90ZWluID09IlRGQ1AyTDEiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKCBjb2xzID0gYygiY2FxdGwiLCJlcXRsIiwicHF0bCIpLCBuYW1lc190byA9ICJxdGxfdHlwZSIsIHZhbHVlc190byA9ICJsb2QiKSAlPiUgCiAgbXV0YXRlKCBxdGxfdHlwZSA9IGZhY3RvciggcXRsX3R5cGUsIGxldmVscyA9IGMoImNhcXRsIiwiZXF0bCIsInBxdGwiKSkpICU+JSAKICBnZ3Bsb3QoKSsKICAgIGFlcyggCiAgICAgIHg9IHBvc19icCwKICAgICAgeSA9IGxvZCwKICAgICAgY29sID0gcXRsX3R5cGUKICAgICAgKSsKICAgIGdlb21fbGluZSggc2l6ZSA9IDEuNSkrCiAgICB0aGVtZV9wdWJjbGVhbiggYmFzZV9zaXplID0gMTgpKwogIHNjYWxlX2NvbG9yX21hbnVhbCggdmFsdWVzID0gYyhxdGwuY29sb3JzW1siYXRhYyJdXSxxdGwuY29sb3JzW1sicm5hIl1dLHF0bC5jb2xvcnNbWyJwcm90Il1dKSwgCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJjYVFUTCIsImVRVEwiLCJwUVRMIikpKwogIHhsYWIocGFzdGUwKCJDaHIgIix0ZmNwMmwxX3F0bCRwZWFrX2NociwiIGxvY2F0aW9uIChicCkiKSkrCiAgeWxhYiggIkxPRCBzY29yZSIpKwogIGxhYnMoY29sID0gIlFUTCB0eXBlIikrCmdlb21fc2VnbWVudCggbWFwcGluZyA9IGFlcyh4ID0gZ2VuZV9zdGFydCwgeGVuZCA9IGdlbmVfZW5kKSwgeSA9IDAsIHllbmQgPSAxLCBjb2wgPSAiYmxhY2siLCBzaXplID0gMikgKwogIGdlb21fdGV4dCggbWFwcGluZyA9IGFlcyggeD0gbWlkcG9pbnQpLCB5ID0gMiwgbGFiZWwgPSJUZmNwMmwxIiwgc2l6ZSA9NiwgY29sID0gImJsYWNrIiwgZm9udGZhY2UgPSAiaXRhbGljIikgKwogIHlsaW0oMCwxNSktPiB0ZmNwMmwxX2xvZF9wbG90Cgpic3ByeV9wbG90IDwtIGdnYXJyYW5nZSggYnNwcnlfbG9kX3Bsb3QsIGJzcHJ5X2hhcGxvdHlwZV9wbG90LAogICAgICAgICAgICAgICAgICAgICAgICAgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGhzID0gYygwLjcsIDAuNCkpCgp0ZmNwMmwxX3Bsb3QgPC0gZ2dhcnJhbmdlKCB0ZmNwMmwxX2xvZF9wbG90LCB0ZmNwMmwxX2hhcGxvdHlwZV9wbG90LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aHMgPSBjKDAuNywgMC40KSApCgpmaWd1cmVfNEMgPC0gZ2dhcnJhbmdlKCBic3ByeV9wbG90LCB0ZmNwMmwxX3Bsb3QsIG5yb3cgPSAyKQoKCmZpZ3VyZV80QwoKYGBgCgo8YnI+CgpRVEwgc2NhbiBhbmQgZWZmZWN0cyBkYXRhIHVzZWQgaW4gcGxvdHRpbmcgRmlndXJlIDRDIGNhbiBiZSBkb3dubG9hZGVkIGJlbG93LgoKYGBge3IgRmlndXJlNENfZGF0YSwgZmlnLmNhcD0iUVRMIHNjYW5zIHVzZWQgdG8gZ2VuZXJhdGUgRmlndXJlIDRDLiJ9CgogbGlzdChGaWd1cmVfNENfZGF0YV9zY2FucywgRmlndXJlXzRDX2RhdGFfZWZmcykgJT4lCiAgZG93bmxvYWR0aGlzOjpkb3dubG9hZF90aGlzKAogICAgb3V0cHV0X25hbWUgPSAiRmlndXJlNEMgZGF0YSIsCiAgICBvdXRwdXRfZXh0ZW5zaW9uID0gIi54bHN4IiwKICAgIGJ1dHRvbl9sYWJlbCA9ICJEb3dubG9hZCBGaWd1cmUgNEMgZGF0YSBhcyB4bHN4IiwKICAgIGJ1dHRvbl90eXBlID0gInByaW1hcnkiLAogICAgaGFzX2ljb24gPSBUUlVFLAogICAgaWNvbiA9ICJmYSBmYS1zYXZlIgogICkKICAKYGBgCgoKCjxicj4KPGJyPgoKIyMjIEZpZ3VyZSA0RDogcFFUTCBob3RzcG90cwoKYGBge3IgRmlndXJlXzREX3ByZXB9CgojIEdldCBwUVRMIGhvdHNwb3RzCiMgcHJlcCB0aGUgb2JqZWN0cwptYXBfZGF0MiRjaHJvbUYgPC0gZmFjdG9yKG1hcF9kYXQyJGNocm9tLCBsZXZlbHMgPSBjKGFzLmNoYXJhY3RlcigxOjE5KSwgIlgiKSkKY2hyb21fbWFya2VycyA8LSBzZWxlY3QobWFwX2RhdDIsIGNocm9tRiwgbikgJT4lCiAgcmVuYW1lKGNocm9tID0gY2hyb21GKSAlPiUKICBncm91cF9ieShjaHJvbSkgJT4lCiAgc3VtbWFyaXplKHN0YXJ0ID0gbWluKG4pLCBlbmQgPSBtYXgobikpICU+JQogIEdlbm9taWNSYW5nZXM6OkdSYW5nZXMoKQp3aW5kb3dzIDwtIHVubGlzdChHZW5vbWljUmFuZ2VzOjpzbGlkaW5nV2luZG93cyhjaHJvbV9tYXJrZXJzLCB3aWR0aCA9IDUwLCBzdGVwID0gMTApKQptYXJrZXJzX2J5bnVtIDwtIHNlbGVjdChtYXBfZGF0MiwgY2hyb20sIG4pICU+JQogIGRwbHlyOjpyZW5hbWUoc3RhcnQgPSBuKSAlPiUKICBtdXRhdGUoZW5kID0gc3RhcnQpICU+JQogIEdlbm9taWNSYW5nZXM6OkdSYW5nZXMoKQoKZGlzdGFudF9lc2NfcHJvdCA8LSBmaWx0ZXIocGVha3MuZXNjX3Byb3RfYW5ub3RhdGVkLCBsb2QgPiA3LjUsICFpcy5uYShsb2NhbCkgJiAhKGxvY2FsKSkgJT4lCiAgc2VsZWN0KHBlYWtfY2hyLCBpbnRlcnBfYnBfcGVhaykgJT4lCiAgZHBseXI6OnJlbmFtZShjaHJvbSA9IHBlYWtfY2hyLCBlbmQgPSBpbnRlcnBfYnBfcGVhaykgJT4lCiAgbXV0YXRlKHN0YXJ0ID0gZW5kKSAlPiUKICBHZW5vbWljUmFuZ2VzOjpHUmFuZ2VzKCkKCmRpc3RhbnRfZXNjX3Byb3Rfc3VnZyA8LSBmaWx0ZXIocGVha3MuZXNjX3Byb3RfYW5ub3RhdGVkLCBsb2QgPiA2LCAhaXMubmEobG9jYWwpICYgIShsb2NhbCkpICU+JQogIHNlbGVjdChwZWFrX2NociwgaW50ZXJwX2JwX3BlYWspICU+JQogIGRwbHlyOjpyZW5hbWUoY2hyb20gPSBwZWFrX2NociwgZW5kID0gaW50ZXJwX2JwX3BlYWspICU+JQogIG11dGF0ZShzdGFydCA9IGVuZCkgJT4lCiAgR2Vub21pY1Jhbmdlczo6R1JhbmdlcygpCgptYXJrZXJzIDwtIHNlbGVjdChtYXBfZGF0MiwgY2hyb20sIHBvc19icCkgJT4lCiAgZHBseXI6OnJlbmFtZShzdGFydCA9IHBvc19icCkgJT4lCiAgbXV0YXRlKGVuZCA9IHN0YXJ0KSAlPiUKICBHZW5vbWljUmFuZ2VzOjpHUmFuZ2VzKCkgIyBsZW5ndGggNjksMDA1Cgp4IDwtIEdlbm9taWNSYW5nZXM6Om5lYXJlc3QoZGlzdGFudF9lc2NfcHJvdF9zdWdnLCBtYXJrZXJzKQp5IDwtIEdlbm9taWNSYW5nZXM6Om5lYXJlc3QoZGlzdGFudF9lc2NfcHJvdCwgbWFya2VycykKCndpbmRvd3MkZGlzdGFudF9lc2NfcHJvdF9zdWdnIDwtIEdlbm9taWNSYW5nZXM6OmNvdW50T3ZlcmxhcHMod2luZG93cywgbWFya2Vyc19ieW51bVt4XSkKd2luZG93cyRkaXN0YW50X2VzY19wcm90IDwtIEdlbm9taWNSYW5nZXM6OmNvdW50T3ZlcmxhcHMod2luZG93cywgbWFya2Vyc19ieW51bVt5XSkKd2luZG93X2NvdW50cyA8LSB0aWJibGUoCiAgY2hyb20gPSBhcy5jaGFyYWN0ZXIoR2Vub21pY1Jhbmdlczo6c2VxbmFtZXMod2luZG93cykpLAogIHN0YXJ0ID0gR2Vub21pY1Jhbmdlczo6c3RhcnQod2luZG93cyksIGVuZCA9IEdlbm9taWNSYW5nZXM6OmVuZCh3aW5kb3dzKSwKICBkaXN0YW50X2VzY19wcm90ID0gd2luZG93cyRkaXN0YW50X2VzY19wcm90LAogIGRpc3RhbnRfZXNjX3Byb3Rfc3VnZyA9IHdpbmRvd3MkZGlzdGFudF9lc2NfcHJvdF9zdWdnLAopCm1tIDwtIG1hdGNoKHdpbmRvd19jb3VudHMkc3RhcnQsIG1hcF9kYXQyJG4pCm0yIDwtIG1hdGNoKHdpbmRvd19jb3VudHMkZW5kLCBtYXBfZGF0MiRuKQp3aW5kb3dfY291bnRzJHBvc19jTV9zdGFydCA8LSBtYXBfZGF0MiRwb3NfY01bbW1dCndpbmRvd19jb3VudHMkcG9zX2JwX3N0YXJ0IDwtIG1hcF9kYXQyJHBvc19icFttbV0Kd2luZG93X2NvdW50cyRwb3NfY01fZW5kIDwtIG1hcF9kYXQyJHBvc19jTVttMl0Kd2luZG93X2NvdW50cyRwb3NfYnBfZW5kIDwtIG1hcF9kYXQyJHBvc19icFttMl0Kd2luZG93X2NvdW50cyA8LSB3aW5kb3dfY291bnRzICU+JQogIG11dGF0ZShtaWRwb2ludCA9IChwb3NfY01fZW5kICsgcG9zX2NNX3N0YXJ0KSAvIDIsIDQpCgp4IDwtIHNlbGVjdCh3aW5kb3dfY291bnRzLCBjaHJvbSwgc3RhcnRzX3dpdGgoInBvc19icCIpLCBzdGFydHNfd2l0aCgiZGlzdGFudCIpKSAlPiUKICBmaWx0ZXIoIGRpc3RhbnRfZXNjX3Byb3QgPiBxdWFudGlsZShkaXN0YW50X2VzY19wcm90LDAuOTk1KSB8CiAgICAgICAgICBkaXN0YW50X2VzY19wcm90X3N1Z2cgPiBxdWFudGlsZShkaXN0YW50X2VzY19wcm90X3N1Z2csMC45OTUpICkKCmJhbmRzLmVzYy5wcm90IDwtIHggJT4lCiAgcmVuYW1lKHN0YXJ0ID0gcG9zX2JwX3N0YXJ0LCBlbmQgPSBwb3NfYnBfZW5kKSAlPiUKICBHZW5vbWljUmFuZ2VzOjpHUmFuZ2VzKCkgJT4lCiAgR2Vub21pY1Jhbmdlczo6cmVkdWNlKCkKIyByZWR1Y2UgY29sbGFwc2VzIG92ZXJsYXBwaW5nIHdpbmRvd3MgaW50byBvbmUgYmlnIHdpbmRvdy4gCmJhbmRzLmVzYy5wcm90JGRpc3RhbnRfZXNjX3Byb3QgPC0gR2Vub21pY1Jhbmdlczo6Y291bnRPdmVybGFwcyhiYW5kcy5lc2MucHJvdCwgZGlzdGFudF9lc2NfcHJvdCkKYmFuZHMuZXNjLnByb3QkZGlzdGFudF9lc2NfcHJvdF9zdWdnIDwtIEdlbm9taWNSYW5nZXM6OmNvdW50T3ZlcmxhcHMoYmFuZHMuZXNjLnByb3QsIGRpc3RhbnRfZXNjX3Byb3Rfc3VnZykKCiMgUGxvdCBob3RzcG90cwpiYW5kcy5lc2MucHJvdCAlPiUgCiAgYXNfdGliYmxlKCkgJT4lIAogIHNlbGVjdCggY2hyb20gPSBzZXFuYW1lcywgc3RhcnQsIGVuZCwgZGlzdGFudF9lc2NfcHJvdCkgJT4lIAogIG11dGF0ZSggaG90c3BvdF9taWRwb2ludCA9IChzdGFydCtlbmQpLzIgKSAlPiUgCiAgIyBhZGRpbmcgYWxsIHRoZSBtYXJrZXIgbG9jYXRpb25zIHRvIG1hdGNoIGF4ZXMKICByYmluZCggKG1hcF9kYXQyICU+JSAKICAgICAgICAgICAgICBzZWxlY3QoIGNocm9tLCBzdGFydCA9IHBvc19icCwgZW5kID1wb3NfYnApICU+JSAKICAgICAgICAgICAgICBtdXRhdGUoIGRpc3RhbnRfZXNjX3Byb3QgPSAwLAogICAgICAgICAgICAgICAgICAgICAgaG90c3BvdF9taWRwb2ludCA9IHN0YXJ0KSkpICU+JSAKICBtdXRhdGUoIGNocm9tID0gZmFjdG9yKGNocm9tLCBsZXZlbHMgPSBjKHNlcSgxOjE5KSwiWCIpKSApIC0+IHBxdGxfY291bnRzCgojIGFkZGluZyBhbGwgdGhlIG1hcmtlcnMgd2l0aCAwIGhvdHNwb3QgdmFsdWVzIHRvIG1hdGNoIHRoZSBheGVzCnBxdGxfY291bnRzJG1pZHBvaW50X29mZnNldCA8LSBwcXRsX2NvdW50cyRob3RzcG90X21pZHBvaW50ICsgY2hyb21fbGVuc19vZmZzZXRbcHF0bF9jb3VudHMkY2hyb21dCgpGaWd1cmU0RF9kYXRhIDwtIHBxdGxfY291bnRzICU+JSAKICBzZWxlY3QoCiAgICBDaHIgPSBjaHJvbSwgCiAgICBgT2Zmc2V0dGVkIGhvdHNwb3QgbWlkcG9pbnQgKGJwKWAgPSBtaWRwb2ludF9vZmZzZXQsCiAgICBgIyBvZiBkaXN0YW50IHBRVExgID0gZGlzdGFudF9lc2NfcHJvdAogICkKCmBgYAoKCmBgYHtyIEZpZ3VyZV80RF9wbG90LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuY2FwID0gIkZpZ3VyZSA0RDogSGlzdG9ncmFtIGRlcGljdGluZyB0aGUgbnVtYmVyIG9mIHRvdGFsIGRpc3RhbnQgcFFUTCBmb3JtaW5nIGhvdHNwb3RzIGFjcm9zcyB0aGUgZ2Vub21lLiIsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTN9CgoKIyBncmFwaGljYWwgcHJlcCBmb3IgY2hyb21vc29tZSBsb2NhdGlvbnMKY2hyb21zIDwtIGMoYXMuY2hhcmFjdGVyKDE6MTkpLCAiWCIpCmNocm9tX2xlbnMgPC0gYyggMTk1NDMxNTU5LCAxODIxMDc2NzAsIDE2MDAxNzEwNCwgMTU2NDk2MDcxLCAxNTE4MzM2MjAsIDE0OTcyMTg3NCwgMTQ1NDM0NjkzLCAxMjkzOTk0NjgsIDEyNDU4MjY1MCwgMTMwNjg1NDE5LCAxMjIwNzg2NTAsIDEyMDEyMDYyMiAsMTIwMzg3MjcyLCAxMjQ4Njc3MjUsIDEwNDAxNTQ1MiwgOTgxODAwMDIsIDk0OTg0NDMyLCA5MDY3MjU5NiwgNjE0MTczMTAgLCAxNzEwMjgzMDApCm5hbWVzKGNocm9tX2xlbnMpIDwtIGNocm9tcwpjaHJvbV9sZW5zX29mZnNldCA8LSBjdW1zdW0oY2hyb21fbGVucykgLSBjaHJvbV9sZW5zCmNocm9tX2xlbnNfbWlkcHQgPC0gY2hyb21fbGVuc19vZmZzZXQgKyBjaHJvbV9sZW5zIC8gMgoKRmlndXJlNERfZGF0YSAlPiUgCiAgZ2dwbG90KCkrCiAgYWVzKCB4ID0gYE9mZnNldHRlZCBob3RzcG90IG1pZHBvaW50IChicClgLCAKICAgICAgIHkgPSBgIyBvZiBkaXN0YW50IHBRVExgKSsKICBnZW9tX2Jhciggc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMTAwLCBjb2wgPXF0bC5jb2xvcnNbWyJwcm90Il1dLCBmaWxsPSBxdGwuY29sb3JzW1sicHJvdCJdXSApKwogIHRoZW1lX3B1YmNsZWFuKGJhc2Vfc2l6ZSA9IDE2KSsKICBzY2FsZV94X2NvbnRpbnVvdXMoIG5hbWUgPSAiQ2hyIiwKICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGNocm9tX2xlbnNfbWlkcHQsIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gbmFtZXMoY2hyb21fbGVucyksIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gLjAyKSApKwogIHhsYWIoIiIpKwogIHlsYWIoIiMgb2YgZGlzdGFudCBwUVRMIikrCiAgdGhlbWUoIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSAtPiB0cmFuc19iYW5kX3Bsb3QKCnRyYW5zX2JhbmRfcGxvdAoKYGBgCgo8YnI+CgpEYXRhIHVzZWQgaW4gcGxvdHRpbmcgRmlndXJlIDREIGNhbiBiZSBkb3dubG9hZGVkIGJlbG93LgoKYGBge3IgRmlndXJlXzREX2RhdGEsIGZpZy5jYXA9IkRhdGEgdXNlZCBpbiBwbG90dGluZyBGaWd1cmUgNEQuIiwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KCmxpc3QoRmlndXJlNERfZGF0YSkgJT4lIAogIGRvd25sb2FkdGhpczo6ZG93bmxvYWRfdGhpcygKICAgIG91dHB1dF9uYW1lID0gIkZpZ3VyZTREIGRhdGEiLAogICAgb3V0cHV0X2V4dGVuc2lvbiA9ICIueGxzeCIsCiAgICBidXR0b25fbGFiZWwgPSAiRG93bmxvYWQgRmlndXJlIDREIGRhdGEgYXMgeGxzeCIsCiAgICBidXR0b25fdHlwZSA9ICJwcmltYXJ5IiwKICAgIGhhc19pY29uID0gVFJVRSwKICAgIGljb24gPSAiZmEgZmEtc2F2ZSIKICApCgpgYGAKCjxicj4KCiMjIyMgVGFibGUgUzY6IExpc3Qgb2YgcFFUTCBob3RzcG90cyBhbmQgdGhlaXIgdGFyZ2V0IHByb3RlaW5zLgoKVGhlIGRldGFpbHMgb2YgZWFjaCBwUVRMIGhvdHNwb3Qgc3VjaCBhcyBjaHJvbW9zb21hbCBsb2NhdGlvbiwgc3RhcnQsIGVuZCwgd2lkdGggYW5kIHRoZSBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgKExPRCA+IDcuNSkgYW5kIHN1Z2dlc3RpdmUgKExPRCA+IDYpIHBRVEwgZm91bmQgYXJlIGxpc3RlZC4gRm9yIGVhY2gsIHRoZSBzdWdnZXN0aXZlIGRpc3RhbnQgcFFUTCBmb3VuZCB3aXRoaW4gdGhlIGhvdHNwb3QgaXMgbGlzdGVkIHdpdGggZ2VuZSBhbm5vdGF0aW9ucyBhbmQgUVRMIGRldGFpbHMgYXMgd2VsbC4gCgpgYGB7ciBUYWJsZV9TNl9nZW5lcmF0ZSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KCiMgUVRMIENocm9tb3NvbWUJUVRMIFN0YXJ0IChicCkJUVRMIEVuZCAoYnApCVFUTCBXaWR0aCAoYnApCU51bWJlciBvZiBTaWduaWZpY2FudCBEaXN0YW50IHBRVEwgKExPRCA+IDcuNSkJTnVtYmVyIG9mIFN1Z2dlc3RpdmUgRGlzdGFudCBwUVRMIChMT0QgPiA2KQpiYW5kcy5lc2MucHJvdCAlPiUgCiAgYXNfdGliYmxlKCkgJT4lIAogIGZpbHRlcihkaXN0YW50X2VzY19wcm90ID4gMjApICU+JSAKICBzZWxlY3QoCiAgICBgUVRMIEhvdHNwb3QgQ2hyb21vc29tZWAgPSBzZXFuYW1lcywKICAgIGBRVEwgSG90c3BvdCBTdGFydCAoYnApYCA9IHN0YXJ0LAogICAgYFFUTCBIb3RzcG90IEVuZCAoYnApYCA9IGVuZCwgCiAgICBgUVRMIEhvdHNwb3QgV2lkdGggKGJwKWAgPSB3aWR0aCwKICAgIGBOdW1iZXIgb2YgU2lnbmZpaWNhbnQgRGlzdGFudCBwUVRsIChMT0QgPiA3LjUpYCA9IGRpc3RhbnRfZXNjX3Byb3QsCiAgICBgTnVtYmVyIG9mIFN1Z2dlc3RpdmUgRGlzdGFudCBwUVRsIChMT0QgPiA2KWAgPSBkaXN0YW50X2VzY19wcm90X3N1Z2cKICApIC0+IHRhYmxlczZfc2hlZXQxCgoKYmFuZHMuZXNjLnByb3QgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBmaWx0ZXIoZGlzdGFudF9lc2NfcHJvdCA+IDIwKSAtPiBiYW5kc19lc2NfcHJvdF9zaWduaWYKCnBlYWtzLmVzY19wcm90X2Fubm90YXRlZCAlPiUgCiAgZmlsdGVyKCBwZWFrX2NociA9PSA0KSAlPiUgCiAgZmlsdGVyKAogICAgbG9jYWwgPT0gRkFMU0UgJiAKICAgICAgaW50ZXJwX2JwX3BlYWsgPj0gYmFuZHNfZXNjX3Byb3Rfc2lnbmlmJHN0YXJ0WzFdICYKICAgICAgaW50ZXJwX2JwX3BlYWsgPD0gYmFuZHNfZXNjX3Byb3Rfc2lnbmlmJGVuZFsxXSAgJgogICAgICBsb2QgPiA2CiAgKSAlPiUgCiAgc2VsZWN0KAogICAgYFByb3RlaW4gSURgID0gcHJvdGVpbl9pZCwgCiAgICBgR2VuZSBJRGAgPSBlbnNlbWJsX2dlbmVfaWQsCiAgICBgTUdJIFN5bWJvbGAgPSBtZ2lfc3ltYm9sLAogICAgYEdlbmUgQ2hyYCA9IGdlbmVfY2hyLAogICAgYEdlbmUgU3RhcnQgKGJwKWAgPSBnZW5lX3N0YXJ0LAogICAgYEdlbmUgRW5kIChicClgID0gZ2VuZV9lbmQsIAogICAgYFFUTCBDaHJgID0gcGVha19jaHIsCiAgICBgUVRMIFBvc2l0aW9uIChjTSlgID0gcGVha19jTSwKICAgIGBRVEwgUG9zaXRpb24gKGJwKWAgPSBpbnRlcnBfYnBfcGVhaywgCiAgICBgTE9EIFNjb3JlYCA9IGxvZAogICkgJT4lIAogICAgbXV0YXRlX2lmKCBpcy5udW1lcmljLCByb3VuZCAsMiktPiB0YWJsZXM2X3NoZWV0MgoKcGVha3MuZXNjX3Byb3RfYW5ub3RhdGVkICU+JSAKICBmaWx0ZXIoIHBlYWtfY2hyID09IDkpICU+JSAKICBmaWx0ZXIoCiAgICBsb2NhbCA9PSBGQUxTRSAmIAogICAgICBpbnRlcnBfYnBfcGVhayA+PSBiYW5kc19lc2NfcHJvdF9zaWduaWYkc3RhcnRbMl0gJgogICAgICBpbnRlcnBfYnBfcGVhayA8PSBiYW5kc19lc2NfcHJvdF9zaWduaWYkZW5kWzJdICAmCiAgICAgIGxvZCA+IDYKICApICU+JSAKICBzZWxlY3QoCiAgICBgUHJvdGVpbiBJRGAgPSBwcm90ZWluX2lkLCAKICAgIGBHZW5lIElEYCA9IGVuc2VtYmxfZ2VuZV9pZCwKICAgIGBNR0kgU3ltYm9sYCA9IG1naV9zeW1ib2wsCiAgICBgR2VuZSBDaHJgID0gZ2VuZV9jaHIsCiAgICBgR2VuZSBTdGFydCAoYnApYCA9IGdlbmVfc3RhcnQsCiAgICBgR2VuZSBFbmQgKGJwKWAgPSBnZW5lX2VuZCwgCiAgICBgUVRMIENocmAgPSBwZWFrX2NociwKICAgIGBRVEwgUG9zaXRpb24gKGNNKWAgPSBwZWFrX2NNLAogICAgYFFUTCBQb3NpdGlvbiAoYnApYCA9IGludGVycF9icF9wZWFrLCAKICAgIGBMT0QgU2NvcmVgID0gbG9kCiAgKSAlPiUgCiAgICBtdXRhdGVfaWYoIGlzLm51bWVyaWMsIHJvdW5kICwyKSAtPiB0YWJsZXM2X3NoZWV0MwoKCnBlYWtzLmVzY19wcm90X2Fubm90YXRlZCAlPiUgCiAgZmlsdGVyKCBwZWFrX2NociA9PSAxNSkgJT4lIAogIGZpbHRlcigKICAgIGxvY2FsID09IEZBTFNFICYgCiAgICAgIGludGVycF9icF9wZWFrID49IGJhbmRzX2VzY19wcm90X3NpZ25pZiRzdGFydFszXSAmCiAgICAgIGludGVycF9icF9wZWFrIDw9IGJhbmRzX2VzY19wcm90X3NpZ25pZiRlbmRbM10gICYKICAgICAgbG9kID4gNgogICkgJT4lIAogIHNlbGVjdCgKICAgIGBQcm90ZWluIElEYCA9IHByb3RlaW5faWQsIAogICAgYEdlbmUgSURgID0gZW5zZW1ibF9nZW5lX2lkLAogICAgYE1HSSBTeW1ib2xgID0gbWdpX3N5bWJvbCwKICAgIGBHZW5lIENocmAgPSBnZW5lX2NociwKICAgIGBHZW5lIFN0YXJ0IChicClgID0gZ2VuZV9zdGFydCwKICAgIGBHZW5lIEVuZCAoYnApYCA9IGdlbmVfZW5kLCAKICAgIGBRVEwgQ2hyYCA9IHBlYWtfY2hyLAogICAgYFFUTCBQb3NpdGlvbiAoY00pYCA9IHBlYWtfY00sCiAgICBgUVRMIFBvc2l0aW9uIChicClgID0gaW50ZXJwX2JwX3BlYWssIAogICAgYExPRCBTY29yZWAgPSBsb2QKICApICU+JSAKICAgIG11dGF0ZV9pZiggaXMubnVtZXJpYywgcm91bmQgLDIpIC0+IHRhYmxlczZfc2hlZXQ0CgpgYGAKCjxicj4KCgpgYGB7ciBUYWJsZV9TNl9kaXNwbGF5LCBlY2hvID0gRkFMU0V9CgoKCiMgd3JpdGV4bDo6d3JpdGVfeGxzeCggbGlzdCggcFFUTF9ob3RzcG90cyA9IHRhYmxlczZfc2hlZXQxLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgIENocjRfaG90c3BvdCA9IHRhYmxlczZfc2hlZXQyLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgIENocjlfaG90c3BvdCA9IHRhYmxlczZfc2hlZXQzLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgIENocjE1X2hvdHNwb3QgPSB0YWJsZXM2X3NoZWV0NCksCiMgICAgICAgICAgICAgICAgICAgICBwYXRoID0gaGVyZSgiVGFibGVTNl9wUVRMX2hvdHNwb3RzLnhsc3giKSwKIyAgICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IFRSVUUsCiMgICAgICAgICAgICAgICAgICAgICBmb3JtYXRfaGVhZGVycyA9IFRSVUUKIyAgICAgICAgICAgICAgICAgICAgICkKIyAKCiMgeGZ1bjo6ZW1iZWRfZmlsZShoZXJlKCJUYWJsZV9TNi54bHN4IikpCgpkb3dubG9hZF9maWxlKAogIHBhdGggPSBoZXJlKCJUYWJsZV9TNi54bHN4IiksCiAgb3V0cHV0X25hbWUgPSAiVGFibGVfUzYiLAogIGJ1dHRvbl9sYWJlbCA9ICJEb3dubG9hZCBUYWJsZV9TNi54bHN4IiwKICBidXR0b25fdHlwZSA9ICJwcmltYXJ5IiwKICBoYXNfaWNvbiA9IFRSVUUsCiAgaWNvbiA9ICJmYSBmYS1zYXZlIiwKICBzZWxmX2NvbnRhaW5lZCA9IEZBTFNFCikKCgpgYGAKCjxicj4KCiMjIyMgRmlndXJlIFM0QS1COiBEZXRhaWxzIG9mIHRoZSBwUVRMIGhvdHNwb3Qgb24gY2hyb21vc29tZSAxNQoKYGBge3IgRmlndXJlX1M0QSwgZmlnLmNhcD0iRmlndXJlIFM0QTogVGhlIGFsbGVsaWMgc3BsaXQgb2JzZXJ2ZWQgaW4gcHJldmlvdXNseSBkZXNjcmliZWQgZVFUTCBob3RzcG90IG9uIGNocm9tb3NvbWUgMTUgaXMgYWxzbyBvYnNlcnZlZCBmb3IgdGhlIHBRVEwgaG90c3BvdC4gSGVhdG1hcCBzaG93aW5nIGhhcGxvdHlwZSBlZmZlY3RzIGF0IHN1Z2dlc3RpdmUgZGlzdGFudCBwUVRMIHBlYWtzIChMT0QgPiA2KSB3aXRoaW4gdGhlIGNocm9tb3NvbWUgMTUgaG90c3BvdC4iLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04fQoKCmNocjE1LnBRVEwgPC0gcGVha3MuZXNjX3Byb3Qud0VmZnMgJT4lCiAgZmlsdGVyKHBlYWtfY2hyID09IDE1KSAlPiUKICBmaWx0ZXIobG9kLmVzY19wcm90ID4gNiAmICFsb2NhbC5lc2NfcHJvdCAmICFpcy5uYShwcm90ZWluX2lkKSAmCiAgICBpbnRlcnBfYnBfcGVhay5lc2NfcHJvdCA+IGZpbHRlcihiYW5kc19lc2NfcHJvdF9zaWduaWYpJHN0YXJ0WzNdICYKICAgIGludGVycF9icF9wZWFrLmVzY19wcm90IDwgZmlsdGVyKGJhbmRzX2VzY19wcm90X3NpZ25pZikkZW5kWzNdKQoKY2hyMTUuYWxsLmdlbmVzLndlZmYubWF0IDwtIGNocjE1LnBRVEwgJT4lCiAgZmlsdGVyKCFpcy5uYShBLmVzY19wcm90KSkgJT4lCiAgc2VsZWN0KGMocGFzdGUwKExFVFRFUlNbMTo4XSwgIi5lc2NfcHJvdCIpLCAibWdpX3N5bWJvbCIpKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygibWdpX3N5bWJvbCIpICU+JQogIGFzLm1hdHJpeCgpICU+JQogIHQoKQoKYW5ub3RhdGlvbl9yb3cgPC0gZGF0YS5mcmFtZShzdHJhaW4gPSBjKCJBSiIsICJCNiIsICIxMjkiLCAiTk9EIiwgIk5aTyIsICJDQVNUIiwgIlBXSyIsICJXU0IiKSkKcm93bmFtZXMoYW5ub3RhdGlvbl9yb3cpIDwtIHJvd25hbWVzKGNocjE1LmFsbC5nZW5lcy53ZWZmLm1hdCkKCmFubm90LmNvbG9ycyA8LSBsaXN0KAogIHN0cmFpbiA9IGMoCiAgIGMoQUogPSAiI0YwRTQ0MiIsIEI2ID0gIiM1NTU1NTUiLCBgMTI5YCA9ICIjRTY5RjAwIiwgTk9EID0gIiMwMDcyQjIiLAogICBOWk8gPSAiIzU2QjRFOSIsIENBU1QgPSAiIzAwOUU3MyIsIFBXSyA9ICIjRDU1RTAwIiwgV1NCID0gIiNDQzc5QTciKQogICksCiAgbWF0Y2ggPSBjKEVTQ19wUVRMID0gcXRsLmNvbG9yc1tbInByb3QiXV0sIHNoYXJlZCA9IHF0bC5jb2xvcnNbWyJzaGFyZWQiXV0pCikKCgoocGhlYXRtYXAoY2hyMTUuYWxsLmdlbmVzLndlZmYubWF0LAogIGNsdXN0ZXJfcm93cyA9IFQsIHNob3dfcm93bmFtZXMgPSBGQUxTRSwKICBjbHVzdGVyX2NvbHMgPSBULCBzaG93X2NvbG5hbWVzID0gRkFMU0UsCiAgY2x1c3RlcmluZ19tZXRob2QgPSAiY29tcGxldGUiLAogIHNjYWxlID0gIm5vbmUiLAogIGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29scyA9ICJjb3JyZWxhdGlvbiIsCiAgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gImNvcnJlbGF0aW9uIiwKICBtYWluID0gIkZvdW5kZXIgYWxsZWxlIGVmZmVjdHMgb2Ygc3VnZ2VzdGl2ZSBwUVRMIHdpdGhpbiBjaHIgMTUgaG90c3BvdCIsCiAgI2Fubm90YXRpb25fY29sID0gYW5ub3RhdGlvbiwKICBhbm5vdGF0aW9uX3JvdyA9IGFubm90YXRpb25fcm93LAogIGFubm90YXRpb25fY29sb3JzID0gYW5ub3QuY29sb3JzLCBjdXRyZWVfcm93cyA9IDIsCiAgY2VsbHdpZHRoID0gMwopKSAKCgpgYGAKCjxicj4KCmBgYHtyIEZpZ3VyZVM0QiwgIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01LCBmaWcuY2FwPSJGaWd1cmUgUzRCOiBNZWRpYXRpb24gYW5hbHlzaXMgaWRlbnRpZmllcyBMaWZyIHRyYW5zY3JpcHQgYWJ1bmRhbmNlIGFzIHRoZSBiZXN0IG1lZGlhdG9yIGZvciBjaHJvbW9zb21lIDE1IHBRVEwgaG90c3BvdC4gRGVjcmVhc2UgaW4gTE9EIHNjb3JlcyBkdWUgdG8gbWVkaWF0aW9uIGlzIHBsb3R0ZWQgZm9yIHRoZSB0b3AgZml2ZSBtZWRpYXRvcnMgaW4gdGhlIHJlZ2lvbiBmb3IgdGhlIHN1Z2dlc3RpdmUgZGlzdGFudCBwUVRMLiBUaGUgcG9pbnRzIGFyZSBjb2xvcmVkIGFuZCBzaXplZCBhY2NvcmRpbmcgdG8gTE9EIGRpZmZlcmVuY2UuIEZvciA2MS8xMzEgc3VnZ2VzdGl2ZSBkaXN0YW50IHBRVEwgcGVha3MgaW4gdGhlIHJlZ2lvbiwgTGlmciB0cmFuc2NyaXB0IGFidW5kYW5jZSBsZWFkcyB0byB0aGUgbGFyZ2VzdCBkcm9wIGluIExPRCB3aGVuIGluY2x1ZGVkIGFzIGEgY292YXJpYXRlIGluIHRoZSBnZW5ldGljIG1hcHBpbmcgbW9kZWwuIn0KCgpwcXRsX3JuYV9tZWRzICU+JQogIGlubmVyX2pvaW4oc2VsZWN0KGNocjE1LnBRVEwsICJ0YXJnZXQuaWQiID0gcHJvdGVpbl9pZCwgInF0bC5jaHIiID0gcGVha19jaHIpKSAtPiBjaHIxNS5ybmEubWVkcwoKcHF0bF9wcm90X21lZHMgJT4lIAogIGlubmVyX2pvaW4oc2VsZWN0KGNocjE1LnBRVEwsICJ0YXJnZXQuaWQiID0gcHJvdGVpbl9pZCwgInF0bC5jaHIiID0gcGVha19jaHIpKSAtPiBjaHIxNS5wcm90Lm1lZHMKCmNocjE1LnJuYS5tZWRzICU+JQogIG11dGF0ZSggdHlwZSA9ICJybmEiKSAlPiUgCiAgcmJpbmQoIGNocjE1LnByb3QubWVkcyAlPiUgIG11dGF0ZSggdHlwZSA9ICJwcm90ZWluIikpICU+JSAKICBtdXRhdGUobWVkaWF0aW9uLmxvZCA9IGlmZWxzZSh0YXJnZXQuc3ltYm9sID09IG1lZGlhdG9yLnN5bWJvbCwgTkEsIG1lZGlhdGlvbi5sb2QpKSAlPiUKICBtdXRhdGUobG9kX2Ryb3AgPSB0YXJnZXQubG9kIC0gbWVkaWF0aW9uLmxvZCkgJT4lCiAgZ3JvdXBfYnkodGFyZ2V0LnN5bWJvbCwgdHlwZSkgJT4lCiAgYXJyYW5nZShtZWRpYXRpb24ubG9kKSAlPiUKICBtdXRhdGUocmFuayA9IHJlcChzZXEoMTpuKCkpKSkgLT4gY2hyMTUubWVkcy5yYW5rZWQKCmNocjE1Lm1lZHMucmFua2VkLnN1bSA8LSBjaHIxNS5tZWRzLnJhbmtlZCAlPiUKICBmaWx0ZXIocmFuayA9PSAxKSAlPiUgI2ZpbHRlcihtZWRpYXRvci5zeW1ib2wgPT0iTGlmciIpICU+JSAgc2VsZWN0KGxvZF9kcm9wKQogIGdyb3VwX2J5KG1lZGlhdG9yLnN5bWJvbCwgdHlwZSkgJT4lCiAgc3VtbWFyaXplKG4gPSBsZW5ndGgodGFyZ2V0LnN5bWJvbCksIG1pbl9kcm9wID0gbWluKGxvZF9kcm9wLCBuYS5ybSA9IFQpLCBtYXhfZHJvcCA9IG1heChsb2RfZHJvcCwgbmEucm0gPSBUKSwgbWVkX2Ryb3AgPSBtZWRpYW4obG9kX2Ryb3AsIG5hLnJtID0gVCkpICU+JQogIGFycmFuZ2UoZGVzYyhuKSkKCiMgbG9va2luZyBhdCB0aGUgdG9wIQpyZXN1bHRzIDwtIGNocjE1Lm1lZHMucmFua2VkICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QobWVkaWF0b3Iuc3ltYm9sLCB0YXJnZXQuc3ltYm9sLCBtZWRpYXRpb24ubG9kLCB0YXJnZXQubG9kKSAlPiUKICBtdXRhdGUobWVkaWF0b3Iuc3ltYm9sID0gc3RyX2MobWVkaWF0b3Iuc3ltYm9sLCAiX3JuYSIpKSAlPiUKICBtdXRhdGUobG9kX2Ryb3AgPSB0YXJnZXQubG9kIC0gbWVkaWF0aW9uLmxvZCkgJT4lCiAgc2VsZWN0KC1tZWRpYXRpb24ubG9kLCAtdGFyZ2V0LmxvZCkgJT4lCiAgZmlsdGVyKChtZWRpYXRvci5zeW1ib2wgJWluJSBzdHJfYyhjaHIxNS5tZWRzLnJhbmtlZC5zdW0kbWVkaWF0b3Iuc3ltYm9sWzE6NV0sICJfcm5hIikpKSAlPiUKICBtdXRhdGUobG9kX2Ryb3AgPSBpZmVsc2UobG9kX2Ryb3AgPCAwLCAwLCBsb2RfZHJvcCksIGxvZF9kcm9wID0gaWZlbHNlKGxvZF9kcm9wID4gNiwgNiwgbG9kX2Ryb3ApKSAlPiUKICByZW5hbWUodGFyZ2V0ID0gdGFyZ2V0LnN5bWJvbCwgTE9EX2RpZmYgPSBsb2RfZHJvcCkKCmdncGxvdChyZXN1bHRzLCBhZXMoeSA9IG1lZGlhdG9yLnN5bWJvbCwgeCA9IHRhcmdldCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IExPRF9kaWZmLCBzaXplID0gZXhwKExPRF9kaWZmKSAvIDMwKSwgYWxwaGEgPSAwLjYpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oCiAgICBjb2xvcnMgPSBjKCJ3aGl0ZSIsICJmaXJlYnJpY2szIiwgIm5hdnkiKSwKICAgIHZhbHVlcyA9IHNjYWxlczo6cmVzY2FsZShjKDAsIDMsIDYpKSwKICAgIG5hbWUgPSAiTE9EXG5kaWZmZXJlbmNlIiwgbGltaXRzID0gYygwLCA2KQogICkgKwogIHNjYWxlX3NpemUoYnJlYWtzID0gMDo2LCBsYWJlbHMgPSBhcy5jaGFyYWN0ZXIoMDo2KSwgcmFuZ2UgPSBjKDAsIDgpKSArCiAgZ3VpZGVzKHNpemUgPSAibm9uZSIpICsKICB0aGVtZV9wdWJjbGVhbihiYXNlX3NpemUgPSAxOCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBoanVzdCA9IDEpLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAwKSwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKQogICkgKwogIHhsYWIoIlRhcmdldCBwUVRMIikrCiAgeWxhYigiTWVkaWF0b3IiKSAtPiBGaWd1cmVfUzRCCgpGaWd1cmVfUzRCCgpgYGAKCjxicj4KCiMjIyMgRmlndXJlIFM0QzogUVRMIG1hcHBpbmcgd2l0aCBHU1ZBIHNjb3JlcwoKCmBgYHtyIEZpZ3VyZV9TNEMsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTksICB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuY2FwPSJGaWd1cmUgUzRDOiBHZW5ldGljIG1hcHBpbmcgd2l0aCBHU1ZBIHNjb3JlcyBvZiBHTyB0ZXJtIFByb3RlaW4gQURQLVJpYm9zeWxhdGlvbiBpZGVudGlmaWVzIGEgbmVhciBzaWduaWZpY2FudCBRVEwgb24gY2hyb21vc29tZSAxNSB3aXRoIHNpbWlsYXIgaGFwbG90eXBlIGVmZmVjdHMgdG8gdGhlIGNocm9tb3NvbWUgMTUgbW9sZWN1bGFyIFFUTCBob3RzcG90LiBPbiB0aGUgbGVmdCwgZ2Vub21lIHNjYW4gc2hvd2luZyBMT0Qgc2NvcmVzIGlzIHBsb3R0ZWQgZm9yIGNocm9tb3NvbWUgMTUuIE9uIHRoZSByaWdodCwgaW5mZXJyZWQgaGFwbG90eXBlIGVmZmVjdHMgYXQgdGhlIFFUTCBwZWFrIGlzIHBsb3R0ZWQuIn0KCgojIFFUTCBtYXBwaW5nIHdpdGggR1NWQSBzY29yZXMKIyBDb21tZW50ZWQgb3V0IGFuZCB0aGUgcmVzdWx0cyBhcmUgc2F2ZWQgdG8gYW4gUkRhdGEgZmlsZSBiZWNhdXNlIGl0IHRha2VzIGEgbG9uZyB0aW1lIHRvIHJ1bi4KZ3N2YV9yZXN1bHRzICU+JQogIGZpbHRlciggQ2F0ZWdvcnkgJWluJSAoc2lnbmlmX3Jlc3VsdHNfdHVrZXkgJT4lIGZpbHRlciggdGVybSAlaW4lIGMoInNleCIsImxpZnJfZ2VubyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcC5hZGouc2lnbmlmICE9ICJucyIgKSkkQ2F0ZWdvcnkgKSAlPiUKICBzZWxlY3QoQ2F0ZWdvcnksIHNhbXBsZWlkLCBFbnJpY2htZW50X1Njb3JlKSAlPiUKICBwaXZvdF93aWRlciggaWRfY29scyA9IHNhbXBsZWlkICwgbmFtZXNfZnJvbSA9IENhdGVnb3J5LCB2YWx1ZXNfZnJvbSA9IEVucmljaG1lbnRfU2NvcmUpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygic2FtcGxlaWQiKSAlPiUKICBhcy5tYXRyaXgoKSAtPiBnc3ZhX3Jlc3VsdHNfc2lnbmlmX21hdAoKIyByYW5rWgpnc3ZhX3Jlc3VsdHNfc2lnbmlmX21hdF9yYW5rWiA8LSBhcHBseShnc3ZhX3Jlc3VsdHNfc2lnbmlmX21hdCwgMixyYW5rWiApCiMgCiMgIyBxdGwgbWFwcGluZwojIGdzdmFfcXRsIDwtIHNjYW4xKCBnZW5vcHJvYnMgPSBwcm9icy5lc2NfcHJvdCwgCiMgICAgICAgICAgICAgICAgICAgIHBoZW5vID0gZ3N2YV9yZXN1bHRzX3NpZ25pZl9tYXRfcmFua1osIAojICAgICAgICAgICAgICAgICAgICBraW5zaGlwID0ga2luc2hpcF9sb2NvLmVzY19wcm90LAojICAgICAgICAgICAgICAgICAgICBhZGRjb3ZhciA9IGNvdmFyLmVzY19wcm90KQojIHNhdmUoIGdzdmFfcXRsLCBmaWxlID0gaGVyZSgiX2RhdGEiLCJHU1ZBX3F0bF9zY2Fucy5SRGF0YSIpKQoKbG9hZChoZXJlKCIuLi9wUVRMX3dlYnNpdGUvX2RhdGEvR1NWQV9xdGxfc2NhbnMuUkRhdGEiKSkKZ3N2YV9xdGxfcGVha3MgPC0gZmluZF9wZWFrcyggZ3N2YV9xdGwsIHRocmVzaG9sZCA9IDcsIGdtYXApCiMgYWRkIGludGVycF9wZWFrX2JwLCBiZWZvcmUsIGFmdGVyCmdzdmFfcXRsX3BlYWtzIDwtIGdzdmFfcXRsX3BlYWtzICU+JSAKICBsZWZ0X2pvaW4oIC4sIGdvYW5ub3Rfd2RlZiAlPiUgc2VsZWN0KGxvZGNvbHVtbj1HT0lELFRFUk0pICU+JSBkaXN0aW5jdCgpKSAlPiUgCiAgbXV0YXRlKCBURVJNID0gaWZlbHNlKCBpcy5uYShURVJNKSwgbG9kY29sdW1uLCBURVJNKSkgJT4lIAogIG11dGF0ZShwaGVub3R5cGU9bG9kY29sdW1uKSAlPiUKICBtdXRhdGUoIHBlYWtfY2hyID0gY2hyLAogICAgICAgICAgcGVha19jTSA9IHBvcykgJT4lCiAgaW50ZXJwX2JwKC4pICNhZGQgYnAgbG9jYXRpb24gZm9yIHBlYWtzCgojIEdldCB0aGUgYm91bmRpbmcgbWFya2VycyBmb3IgZWFjaCBRVEwgcGVhawojIGkuZS4gbWFya2VycyBvbiB0aGUgNjlrIGdyaWQgdGhhdCBhcmUgdXAtIGFuZCBkb3duc3RyZWFtIG9mIHRoZSBwZWFrCnF1ZXJ5IDwtIGdzdmFfcXRsX3BlYWtzICU+JSBkcGx5cjo6c2VsZWN0KHBlYWtfY2hyLCBpbnRlcnBfYnBfcGVhaykgJT4lCiAgICBkcGx5cjo6cmVuYW1lKGNocm9tPXBlYWtfY2hyLCBzdGFydD1pbnRlcnBfYnBfcGVhaykgJT4lIG11dGF0ZShlbmQ9c3RhcnQpICU+JQogICAgR2Vub21pY1Jhbmdlczo6R1JhbmdlcygpCnN1YmplY3QgPC0gc2VsZWN0KG1hcF9kYXQyLCBjaHJvbSwgcG9zX2JwKSAlPiUgZHBseXI6OnJlbmFtZShzdGFydD1wb3NfYnApICU+JQogICAgbXV0YXRlKGVuZD1zdGFydCkgJT4lIEdlbm9taWNSYW5nZXM6OkdSYW5nZXMoKSAgICMgbGVuZ3RoIDY5LDAwNQoKZ3N2YV9xdGxfcGVha3MkYmVmb3JlIDwtIG1hcF9kYXQyJG1hcmtlcltmb2xsb3cocXVlcnksIHN1YmplY3QpXQpnc3ZhX3F0bF9wZWFrcyRhZnRlciA8LSBtYXBfZGF0MiRtYXJrZXJbcHJlY2VkZShxdWVyeSwgc3ViamVjdCldCgojIHBsb3QgUHJvdGVpbiBBRFAgcmlib3N5bGF0aW9uCnJpYm9fc2Nhbl9wbG90IDwtIGdzdmFfcXRsWywiR086MDAwNjQ3MSIsZHJvcD1GQUxTRV0gJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJtYXJrZXIiKSAlPiUgCiAgbGVmdF9qb2luKG1hcF9kYXQyKSAlPiUgCiAgZmlsdGVyKCBjaHIgPT0gMTUpICU+JSAKICBnZ3Bsb3QoKSsKICAgIGFlcyggCiAgICAgIHg9IHBvc19icCwKICAgICAgeSA9IGBHTzowMDA2NDcxYCwKICAgICAgKSsKICBnZW9tX2xpbmUoIHNpemUgPSAxLjUsIGNvbCA9IHF0bC5jb2xvcnNbWyJwcm90Il1dKSsKICB0aGVtZV9wdWJjbGVhbiggYmFzZV9zaXplID0gMTgpKwogIHhsYWIocGFzdGUwKCJDaHIgMTUgbG9jYXRpb24gKGJwKSIpKSsKICB5bGFiKCAiTE9EIHNjb3JlIikrCiAgeWxpbSgwLDgpCgpyaWJvX2VmZnMgPC0gc2NhbjFibHVwKCBnZW5vcHJvYnMgPSBwcm9icy5lc2NfcHJvdFssMTVdLCAKICAgICAgICAgICAgICAgICAgIHBoZW5vID0gZ3N2YV9yZXN1bHRzX3NpZ25pZl9tYXRfcmFua1pbLCJHTzowMDA2NDcxIixkcm9wPUZBTFNFXSwgCiAgICAgICAgICAgICAgICAgICBraW5zaGlwID0ga2luc2hpcF9sb2NvLmVzY19wcm90W1sxNV1dLAogICAgICAgICAgICAgICAgICAgYWRkY292YXIgPSBjb3Zhci5lc2NfcHJvdCkgIApyaWJvX3F0bDwtIGdzdmFfcXRsX3BlYWtzICU+JSAKICBmaWx0ZXIoIHBoZW5vdHlwZSA9PSJHTzowMDA2NDcxIiwgcGVha19jaHIgPT0gMTUpCnJpYm9fZWZmcyA8LSBjb2xNZWFucyhyaWJvX2VmZnNbYyhyaWJvX3F0bCRiZWZvcmUscmlib19xdGwkYWZ0ZXIpLCBMRVRURVJTWzE6OF1dKQoKcmlib19lZmZzICU+JSAKICBhc190aWJibGUocm93bmFtZXMgPSAiZWZmZWN0IiApICU+JSAKICBtdXRhdGUoIHR5cGUgPSAicFFUTCIpICU+JSAKICBtdXRhdGUoIGVmZmVjdCA9IGNhc2Vfd2hlbiggZWZmZWN0ID09ICJBIiB+ICJBSiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdCA9PSAiQiIgfiAiQjYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmZlY3QgPT0gIkMiIH4gIjEyOSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdCA9PSAiRCIgfiAiTk9EIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0ID09ICJFIiB+ICJOWk8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmZlY3QgPT0gIkYiIH4gIkNBU1QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmZlY3QgPT0gIkciIH4gIlBXSyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdCA9PSAiSCIgfiAiV1NCIikpICU+JSAKICBnZ3Bsb3QoKSsKICBhZXMoIHggPSBlZmZlY3QsCiAgICAgICB5ID0gdmFsdWUsIAogICAgICAgZ3JvdXAgPSB0eXBlKSsKICBnZW9tX3BvaW50KHNpemUgPSA0LCBzaG93LmxlZ2VuZCA9IEZBTFNFLCBjb2wgPSBxdGwuY29sb3JzW1sicHJvdCJdXSkrCiAgZ2VvbV9saW5lKHNpemUgPSAxLjIsIHNob3cubGVnZW5kID0gRiwgY29sID0gcXRsLmNvbG9yc1tbInByb3QiXV0pKwogIHRoZW1lX3B1YmNsZWFuKGJhc2Vfc2l6ZSA9IDE4KSsKICB5bGFiKCJIYXBsb3R5cGUgZWZmZWN0cyIpKwogIHhsYWIoIiIpKwogIHlsaW0oLTEsMSkrCiAgZ2VvbV9obGluZSggeWludGVyY2VwdCA9IDApKwogIHRoZW1lKGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkrCiAgY29vcmRfZmxpcCggY2xpcCA9Im9mZiIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgLT4gcmlib19oYXBfcGxvdAoKcmlib19xdGxfcGxvdCA8LSBnZ2FycmFuZ2Uocmlib19zY2FuX3Bsb3QsIHJpYm9faGFwX3Bsb3QsIG5yb3cgPSAxLCB3aWR0aHMgPSBjKDAuNywgMC40KSkKcmlib19xdGxfcGxvdAoKCmBgYAoKPGJyPgo8YnI+CgojIyMgRmlndXJlIDRFOiBTdG9pY2hvbWV0cmljIGJ1ZmZlcmluZyBleGFtcGxlCgoKYGBge3IgRmlndXJlXzRFX3ByZXB9CgpycGFfcXRsIDwtIHBlYWtzLmVzYy5vdmVybGFwLndFZmZzICU+JSAKICBmaWx0ZXIoIGxvZC5lc2NfcHJvdCA+Ny41LCBtZ2lfc3ltYm9sICVpbiUgYygiUnBhMSIsIlJwYTIiLCJScGEzIiksIG1hdGNoJWluJSBjKCJlc2NfcHJvdCIsInNoYXJlZCIpKQoKIyBFZmZlY3RzIHBsb3QKIyAiQS9KIiwgIkI2IiwgIjEyOSIsICJOT0QiLCAiTlpPIiwgIkNBU1QiLCAiUFdLIiwgIldTQiIKcnBhX2VmZmVjdHMgPC0gcGVha3MuZXNjLm92ZXJsYXAud0VmZnMgJT4lIAogIGZpbHRlciggcHJvdGVpbl9pZCAlaW4lIHJwYV9xdGwkcHJvdGVpbl9pZCAsIAogICAgICAgICAgcGVha19jaHIgJWluJSBycGFfcXRsJHBlYWtfY2hyLCAKICAgICAgICAgIG1hdGNoJWluJSBjKCJlc2NfcHJvdCIsInNoYXJlZCIpKSAlPiUgCiAgc2VsZWN0KCBtZ2lfc3ltYm9sLCAKICAgICAgICAgIHBhc3RlMChMRVRURVJTWzE6OF0sICIuZXNjX3Byb3QiKQogICkgCgpycGFfZWZmZWN0c19tYXQgPC0gcnBhX2VmZmVjdHMgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygibWdpX3N5bWJvbCIpICU+JSAgCiAgdCgpCgpGaWd1cmVfNEVfZGF0YV9lZmZzIDwtIHJwYV9lZmZlY3RzICU+JSAKICBtdXRhdGUoIFByb3RlaW49IHRvdXBwZXIobWdpX3N5bWJvbCkpICU+JSAKICBwaXZvdF9sb25nZXIoIGNvbHMgPSBjKHBhc3RlMChMRVRURVJTWzE6OF0sICIuZXNjX3Byb3QiKSksIAogICAgICAgICAgICAgICAgbmFtZXNfdG8gPSBjKCJlZmZlY3QiKSwKICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJwUVRMIGVmZmVjdCIpICU+JSAKICBzZXBhcmF0ZShlZmZlY3QsIHNlcCA9IlsuXSIsIGludG8gPSBjKCJTdHJhaW4iLCJ0eXBlIikpICU+JSAKICBtdXRhdGUoIFN0cmFpbiA9IGNhc2Vfd2hlbiggU3RyYWluID09ICJBIiB+ICJBL0oiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdHJhaW4gPT0gIkIiIH4gIkI2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RyYWluID09ICJDIiB+ICIxMjkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdHJhaW4gPT0gIkQiIH4gIk5PRCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0cmFpbiA9PSAiRSIgfiAiTlpPIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RyYWluID09ICJGIiB+ICJDQVNUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RyYWluID09ICJHIiB+ICJQV0siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdHJhaW4gPT0gIkgiIH4gIldTQiIpKSAKCiMgTE9EIHBsb3RzCnJwYV9wcXRsIDwtIHNjYW4xKGdlbm9wcm9icyA9IHByb2JzLmVzY19wcm90LAogICAgICAgICAgICAgICAgICAgICAgcGhlbm8gPSBleHByWi5lc2NfcHJvdFsscnBhX3F0bCRwcm90ZWluX2lkXSwKICAgICAgICAgICAgICAgICAgICAgIGtpbnNoaXAgPSBraW5zaGlwX2xvY28uZXNjX3Byb3QsCiAgICAgICAgICAgICAgICAgICAgICBhZGRjb3ZhciA9IGNvdmFyLmVzY19wcm90KQoKCkZpZ3VyZV80RV9kYXRhX3NjYW5zIDwtIHJwYV9wcXRsICU+JSAKICBhc190aWJibGUocm93bmFtZXMgPSAibWFya2VyIikgJT4lIAogIGxlZnRfam9pbihtYXBfZGF0MikgICU+JSAKICBmaWx0ZXIoIGNociA9PSBycGFfcXRsJHBlYWtfY2hyWzFdKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKCBjb2xzID0gYygiRU5TTVVTUDAwMDAwMDEyNjI3IiwiRU5TTVVTUDAwMDAwMDk5NjIxIiwiRU5TTVVTUDAwMDAwMDAwNzY3IiksIG5hbWVzX3RvID0gInByb3RlaW5faWQiLCB2YWx1ZXNfdG8gPSAibG9kIikgJT4lIAogIGxlZnRfam9pbiggc2VsZWN0KGFsbC5wcm90cywgcHJvdGVpbl9pZCwgbWdpX3N5bWJvbCkpICU+JSAKICBtdXRhdGUoIFByb3RlaW49IHRvdXBwZXIobWdpX3N5bWJvbCkpICU+JSAKICBtdXRhdGUoIFByb3RlaW4gPSBmYWN0b3IoIFByb3RlaW4sIGxldmVscyA9IGMoIlJQQTEiLCJSUEEyIiwiUlBBMyIpKSkgJT4lIAogIHNlbGVjdCggUHJvdGVpbiwgCiAgICAgICAgICBgTE9EIHNjb3JlYCA9IGxvZCwgCiAgICAgICAgICBgTWFya2VyIFBvc2l0aW9uIChicClgID0gcG9zX2JwKQoKYGBgCgpgYGB7ciBGaWd1cmVfNEVfcGxvdCwgZmlnLmNhcCA9ICJGaWd1cmUgNEU6IEFuIGV4YW1wbGUgb2YgcGh5c2ljYWwgaW50ZXJhY3Rpb24gcHJvcGFnYXRpbmcgdGhlIGVmZmVjdHMgb2YgZ2VuZXRpYyB2YXJpYXRpb24gaXMgcGxvdHRlZC4gT24gdGhlIGxlZnQsIGdlbm9tZSBzY2FuIHNob3dpbmcgTE9EIHNjb3JlcyBhY3Jvc3MgdGhlIGdlbm9tZSBmb3IgcHJvdGVpbnMgUlBBMSwgUlBBMiBhbmQgUlBBMyBpcyBzaG93biB3aXRoIHRoZSBsb2NhdGlvbiBvZiBScGEzIGdlbmUgYW5ub3RhdGVkIG9uIHRoZSB4LSBheGlzLiBPbiB0aGUgcmlnaHQsIHRoZSBpbmZlcnJlZCBmb3VuZGVyIGFsbGVsZSBlZmZlY3RzIGF0IHRoZSBwUVRMIHBlYWsgZm9yIGFsbCB0aHJlZSBnZW5lcyBhcmUgc2hvd24uIiwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9OX0KCgoKRmlndXJlXzRFX2RhdGFfZWZmcyAlPiUgCiAgZ2dwbG90KCkrCiAgYWVzKCB4ID0gU3RyYWluLAogICAgICAgeSA9IGBwUVRMIGVmZmVjdGAsIAogICAgICAgZ3JvdXA9IFByb3RlaW4sIAogICAgICAgY29sID0gUHJvdGVpbikrCiAgZ2VvbV9wb2ludChzaXplID0gNCwgc2hvdy5sZWdlbmQgPSBGKSsKICBnZW9tX2xpbmUoc2hvdy5sZWdlbmQgPSBULCBzaXplID0xLjIpKwogIHNjYWxlX2NvbG9yX21hbnVhbCggdmFsdWVzID0gYyggUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDYsICJCbHVlcyIpWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDYsICJCbHVlcyIpWzZdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDYsICJCbHVlcyIpWzRdKSkrCiAgdGhlbWVfcHViY2xlYW4oYmFzZV9zaXplID0gMTgpKwogIHlsYWIoIkhhcGxvdHlwZSBlZmZlY3RzIikrCiAgeGxhYigiIikrCiAgeWxpbSgtMS42LDEuNikrCiAgZ2VvbV9obGluZSggeWludGVyY2VwdCA9IDApKwogIHRoZW1lKGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkrCiAgbGFicyhzaGFwZSA9ICJQcm90ZWluIikrCiAgIGNvb3JkX2ZsaXAoIGNsaXAgPSJvZmYiKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpIC0+IHJwYV9oYXBsb3R5cGVfcGxvdAoKCkZpZ3VyZV80RV9kYXRhX3NjYW5zICU+JSAKICBnZ3Bsb3QoKSsKICAgIGFlcyggCiAgICAgIHg9IGBNYXJrZXIgUG9zaXRpb24gKGJwKWAsCiAgICAgIHkgPSAgYExPRCBzY29yZWAsCiAgICAgIGNvbCA9IFByb3RlaW4sCiAgICAgICkrCiAgICBnZW9tX2xpbmUoIHNpemUgPSAxLjUpKwogICAgdGhlbWVfcHViY2xlYW4oIGJhc2Vfc2l6ZSA9IDE4KSsKICBzY2FsZV9jb2xvcl9tYW51YWwoIHZhbHVlcyA9IGMoIFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg2LCAiQmx1ZXMiKVszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg2LCAiQmx1ZXMiKVs2XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg2LCAiQmx1ZXMiKVs0XSkpKwogIHhsYWIocGFzdGUwKCJDaHIgNiBsb2NhdGlvbiAoYnApIikpKwogIHlsYWIoICJMT0Qgc2NvcmUiKSsKICBsYWJzKGNvbCA9ICJQcm90ZWluIikrCiAgZ2VvbV9zZWdtZW50KCB4ID0gODI1NTkzNiwgeGVuZCA9ICA4MjU5MTczLCB5ID0gMCwgeWVuZCA9IDEsIGNvbCA9ICJibGFjayIsIHNpemUgPSAyKSArCiAgYW5ub3RhdGUoICJ0ZXh0IiwgeD0gODI1NzU1NCwgeSA9IDIsIGxhYmVsID0iaXRhbGljKFJwYTMpIiwgcGFyc2UgPSBUUlVFLCBzaXplID02KSArCiAgeWxpbSgwLDIwKSAtPiBycGFfbG9kX3Bsb3QKCgpGaWd1cmVfNEUgPC0gZ2dhcnJhbmdlKCBycGFfbG9kX3Bsb3QsIHJwYV9oYXBsb3R5cGVfcGxvdCwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIHdpZHRocyA9IGMoMC43LCAwLjQpICkKCkZpZ3VyZV80RQoKCmBgYAoKPGJyPgoKUVRMIHNjYW5zIGFuZCB0aGUgZWZmZWN0cyB1c2VkIGluIHBsb3R0aW5nIEZpZ3VyZSA0RSBjYW4gYmUgZG93bmxvZGVkIGJlbG93LgoKYGBge3IgRmlndXJlNEVfZGF0YSwgZmlnLmNhcD0iUVRMIHNjYW5zIHVzZWQgaW4gcGxvdHRpbmcgTE9EIHBsb3RzIGluIEZpZ3VyZSA0RS4ifQoKCmxpc3QoRmlndXJlXzRFX2RhdGFfc2NhbnMsIEZpZ3VyZV80RV9kYXRhX2VmZnMpICU+JSAKICAgIGRvd25sb2FkdGhpczo6ZG93bmxvYWRfdGhpcygKICAgIG91dHB1dF9uYW1lID0gIkZpZ3VyZTRFIGRhdGEiLAogICAgb3V0cHV0X2V4dGVuc2lvbiA9ICIueGxzeCIsCiAgICBidXR0b25fbGFiZWwgPSAiRG93bmxvYWQgRmlndXJlIDRFIGRhdGEgYXMgeGxzeCIsCiAgICBidXR0b25fdHlwZSA9ICJwcmltYXJ5IiwKICAgIGhhc19pY29uID0gVFJVRSwKICAgIGljb24gPSAiZmEgZmEtc2F2ZSIKICApCgpgYGAKCjxicj4KPGJyPgoKIyMjIEZpZ3VyZSA0RjogT3ZlcnZpZXcgb2Ygc2lnbmlmaWNhbnQgcFFUTCBvdmVybGFwIHdpdGggY2FRVEwgYW5kIGVRVEwKCgpgYGB7ciBGaWd1cmVfNEYsIGZpZy5jYXAgPSAiRmlndXJlIDRGOiBHcmFwaGljYWwgb3ZlcnZpZXcgb2YgdGhlIGRpZmZlcmVudCBncm91cHMgb2YgcFFUTCB3aGVyZSB0aGUgZ2VuZXRpYyB2YXJpYXRpb24gKFFUTCkgaW5mbHVlbmNlcyBvbmUgb3IgbW9yZSBtb2xlY3VsYXIgbGF5ZXJzLiBNb2xlY3VsYXIgbGF5ZXJzIGxhY2tpbmcgYW55IGltcGFjdCAoaS5lLiwgbm8gUVRMIGFib3ZlIExPRCA+NSB3aXRoIG1hdGNoaW5nIGhhcGxvdHlwZSBlZmZlY3RzKSBhcmUgZGVwaWN0ZWQgaW4gZ3JheS4iLCBvdXQud2lkdGg9IjYwMHB4In0KCgprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJGaWd1cmU0Ri5wbmciKSkKCmBgYAoKPGJyPgoKYGBge3IgRmlndXJlXzRGX2RhdGEsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5jYXA9IkRhdGEgdXNlZCB0byBnZW5lcmF0ZSBGaWd1cmUgNEYuIn0KCmlkcyA8LSB0aHJlZXdheS5zaGFyZWQuc2FtcGxlcyRzYW1wbGVpZApuYW1lcyhpZHMpIDwtIHRocmVld2F5LnNoYXJlZC5zYW1wbGVzJHRvcF9tdWdhCnRocmVld2F5LnNoYXJlZC5wcm9icyA8LSBtZXJnZWQucHJvYnNbaW5kID0gdGhyZWV3YXkuc2hhcmVkLnNhbXBsZXMkdG9wX211Z2FdCnRocmVld2F5LnNoYXJlZC5wcm9icyA8LSByZXBsYWNlX2lkcyh0aHJlZXdheS5zaGFyZWQucHJvYnMsIGlkcykKdGhyZWV3YXkuc2hhcmVkLmtpbnNoaXAgPC0gY2FsY19raW5zaGlwKHRocmVld2F5LnNoYXJlZC5wcm9icywgdHlwZSA9ICJsb2NvIikKdGhyZWV3YXkuc2hhcmVkLmNvdmFyIDwtIG1lcmdlZC5jb3Zhclt0aHJlZXdheS5zaGFyZWQuc2FtcGxlcyR0b3BfbXVnYSwgLCBkcm9wID0gRkFMU0VdCnJvd25hbWVzKHRocmVld2F5LnNoYXJlZC5jb3ZhciApIDwtIHRocmVld2F5LnNoYXJlZC5zYW1wbGVzJHNhbXBsZWlkCgojICMgYWRkaW5nIHNoYXJlZCBkYXRhIG1hdHJpY2VzIHdpdGggbmV3X3N5bWJvbCBpbiB0aGUgY29sdW1uIG5hbWVzCnNoYXJlZC5hdGFjLmRhdGEgPC0gKGNvdW50cy5ub3JtWlt0aHJlZXdheS5zaGFyZWQuc2FtcGxlcyRBVEFDLCB0aHJlZXdheS5zaGFyZWQuZ2VuZXMkcGVha19pZF0pCmNvbG5hbWVzKHNoYXJlZC5hdGFjLmRhdGEpIDwtIHRocmVld2F5LnNoYXJlZC5nZW5lcyRuZXdfc3ltYm9sCnJvd25hbWVzKHNoYXJlZC5hdGFjLmRhdGEpIDwtIHRocmVld2F5LnNoYXJlZC5zYW1wbGVzJHNhbXBsZWlkCgpzaGFyZWQucm5hLmRhdGEgPC0gKGV4cHJaLmVzY19ybmFbdGhyZWV3YXkuc2hhcmVkLnNhbXBsZXMkc2FtcGxlaWQsIHRocmVld2F5LnNoYXJlZC5nZW5lcyRlbnNlbWJsX2dlbmVfaWRdKQpjb2xuYW1lcyhzaGFyZWQucm5hLmRhdGEpIDwtIHRocmVld2F5LnNoYXJlZC5nZW5lcyRuZXdfc3ltYm9sCgpzaGFyZWQucHJvdC5kYXRhIDwtIChleHByWi5lc2NfcHJvdFt0aHJlZXdheS5zaGFyZWQuc2FtcGxlcyRzYW1wbGVpZCwgdGhyZWV3YXkuc2hhcmVkLmdlbmVzJHByb3RlaW5faWRdKQpjb2xuYW1lcyhzaGFyZWQucHJvdC5kYXRhKSA8LSB0aHJlZXdheS5zaGFyZWQuZ2VuZXMkbmV3X3N5bWJvbAoKIyBnZXQgdGhlIHBlYWtzIG9ubHkgZm9yIHNoYXJlZCBnZW5lcwpwZWFrcy5lc2Mub3ZlcmxhcDIgJT4lIAogZmlsdGVyKCBwcm90ZWluX2lkICVpbiUgdGhyZWV3YXkuc2hhcmVkLmdlbmVzJHByb3RlaW5faWQpIC0+IHBlYWtzLnRocmVld2F5LnNoYXJlZC5nZW5lcwoKCiMgdG90YWwgc2lnbmlmaWNhbnQgcFFUTCBmb3IgdGhyZWV3YXkgc2hhcmVkIGdlbmVzCnBlYWtzLmVzY19wcm90X2Fubm90YXRlZCAlPiUgIAogIGZpbHRlciggcHJvdGVpbl9pZCAlaW4lIHRocmVld2F5LnNoYXJlZC5nZW5lcyRwcm90ZWluX2lkLCBsb2QgPjcuNSkgLT4gc2lnbmlmaWNhbnRfcFFUTCAjIDE1ODkKCiMgYW5ub3RhdGluZyBwUVRMCnNpZ25pZmljYW50X3BRVEwgJT4lIAogIHNlbGVjdCggbG9kLmVzY19wcm90ID0gbG9kLCAKICAgICAgICAgIHBlYWtfY2hyLAogICAgICAgICAgcHJvdGVpbl9pZCwKICAgICAgICAgIGxvY2FsKSAlPiUgCiAgaW5uZXJfam9pbiggLiwKICAgICAgICAgICAgICAocGVha3MudGhyZWV3YXkuc2hhcmVkLmdlbmVzICU+JSAKICAgICAgICAgICAgICAgICBzZWxlY3QoIGxvZC5lc2NfcHJvdCwKICAgICAgICAgICAgICAgICAgICAgICAgIHBlYWtfY2hyLAogICAgICAgICAgICAgICAgICAgICAgICAgcHJvdGVpbl9pZCwKICAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoKQogICAgICAgICAgICAgICAgICAgICApCiAgKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkoIGxvZC5lc2NfcHJvdCxwZWFrX2Nocixwcm90ZWluX2lkKSAlPiUgCiAgbXV0YXRlKCBtYXRjaF9hbGwgPSBwYXN0ZTAobWF0Y2gsIGNvbGxhcHNlID0gIiwgIikpICU+JSAKICBzZWxlY3QoLW1hdGNoKSAlPiUgCiAgdW5ncm91cCAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgbXV0YXRlKCBtYXRjaCA9IGNhc2Vfd2hlbigKICAgIG1hdGNoX2FsbCA9PSAiZXNjX3Byb3QiIH4idW5pcXVlIHBRVEwiLAogICAgbWF0Y2hfYWxsID09ICJzaGFyZWRfZVFUTF9wUVRMIiB+InNoYXJlZCBlL3BRVEwiLAogICAgbWF0Y2hfYWxsID09ICJzaGFyZWRfY2FRVExfcFFUTCIgfiJzaGFyZWQgY2EvcFFUTCIsCiAgICBtYXRjaF9hbGwgJWluJSBjKCJzaGFyZWRfZVFUTF9wUVRMLCBzaGFyZWQiLAogICAgICAgICAgICAgICAgICAgICAic2hhcmVkLCBzaGFyZWRfZVFUTF9wUVRMIiwKICAgICAgICAgICAgICAgICAgICAgInNoYXJlZF9lUVRMX3BRVEwsIHNoYXJlZCwgc2hhcmVkX2NhUVRMX2VRVEwiLAogICAgICAgICAgICAgICAgICAgICAic2hhcmVkX2NhUVRMX2VRVEwsIHNoYXJlZCwgc2hhcmVkX2VRVExfcFFUTCIsCiAgICAgICAgICAgICAgICAgICAgICJzaGFyZWRfZVFUTF9wUVRMLCBzaGFyZWRfY2FRVExfZVFUTCwgc2hhcmVkIiwKICAgICAgICAgICAgICAgICAgICAgInNoYXJlZCwgc2hhcmVkX2NhUVRMX2VRVEwsIHNoYXJlZF9lUVRMX3BRVEwiLAogICAgICAgICAgICAgICAgICAgICAic2hhcmVkLCBzaGFyZWRfZVFUTF9wUVRMLCBzaGFyZWRfY2FRVExfZVFUTCIsCiAgICAgICAgICAgICAgICAgICAgICJzaGFyZWRfY2FRVExfZVFUTCwgc2hhcmVkX2VRVExfcFFUTCIsCiAgICAgICAgICAgICAgICAgICAgICJzaGFyZWRfZVFUTF9wUVRMLCBzaGFyZWRfY2FRVExfZVFUTCIsCiAgICAgICAgICAgICAgICAgICAgICJzaGFyZWQsIHNoYXJlZF9jYVFUTF9lUVRMIiwKICAgICAgICAgICAgICAgICAgICAgInNoYXJlZF9jYVFUTF9lUVRMLCBzaGFyZWQiLAogICAgICAgICAgICAgICAgICAgICAic2hhcmVkIgogICAgICAgICAgICAgICAgICAgICApfiJzaGFyZWQgY2EvZS9wUVRMIgogICkpIC0+IHNpZ25pZmljYW50X3BRVExfYW5ub3QgCgojIEkgYW0gYWRkaW5nIGNhUVRML2VRVEwgZGV0YWlscywgaW5jbHVkaW5nIGFsbGVsZSBlZmZlY3RzIHRvIHRoZSBzaWduaWZpY2FudCBwUVRMLgpzaWduaWZpY2FudF9wUVRMX2Fubm90ICU+JSAKICByZW5hbWUoIGxvY2FsLmVzY19wcm90ID0gbG9jYWwpICU+JSAKICBsZWZ0X2pvaW4oCiAgICBwZWFrcy5lc2Mub3ZlcmxhcC53RWZmcyAlPiUgIAogICAgICBzZWxlY3QoIAogICAgICAgIGVuc2VtYmxfZ2VuZV9pZCwgcHJvdGVpbl9pZCwgcGVha19pZCwKICAgICAgICBwZWFrX2NociwgZ2VuZV9jaHIsCiAgICAgICAgbG9kLmVzY19hdGFjLCBsb2QuZXNjX3JuYSwgbG9kLmVzY19wcm90LAogICAgICAgIGxvY2FsLmVzY19hdGFjLCBsb2NhbC5lc2Nfcm5hLCBsb2NhbC5lc2NfcHJvdCwKICAgICAgICBpbnRlcnBfYnBfcGVhay5lc2NfYXRhYywgaW50ZXJwX2JwX3BlYWsuZXNjX3JuYSwgaW50ZXJwX2JwX3BlYWsuZXNjX3Byb3QsCiAgICAgICAgcGFzdGUwKExFVFRFUlNbMTo4XSwiLmVzY19hdGFjIiksCiAgICAgICAgcGFzdGUwKExFVFRFUlNbMTo4XSwiLmVzY19ybmEiKSwKICAgICAgICBwYXN0ZTAoTEVUVEVSU1sxOjhdLCIuZXNjX3Byb3QiKSwKICAgICAgICBiZWZvcmUuZXNjX2F0YWMsIGJlZm9yZS5lc2Nfcm5hLCBiZWZvcmUuZXNjX3Byb3QsCiAgICAgICAgYWZ0ZXIuZXNjX2F0YWMsIGFmdGVyLmVzY19ybmEsIGFmdGVyLmVzY19wcm90LAogICAgICAgIGN1bXN1bV9icC5lc2NfYXRhYywgY3Vtc3VtX2JwLmVzY19ybmEsIGN1bXN1bV9icC5lc2NfcHJvdCwKICAgICAgICBjdW1zdW1fYnBfcGVhay5lc2NfYXRhYywgY3Vtc3VtX2JwX3BlYWsuZXNjX3JuYSwgY3Vtc3VtX2JwX3BlYWsuZXNjX3Byb3QKICAgICAgICApIAogICAgKSAlPiUgCiAgICBtdXRhdGUocXRsX2lkID0gcGFzdGUwKCJxdGxfIiwgMTpuKCkpLAogICAgICAgICBlZmZfc3RhdCA9IGNhc2Vfd2hlbiggaXMubmEoQS5lc2Nfcm5hKSB+ICJtaXNzaW5nIGVRVEwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoQS5lc2NfcHJvdCkgfiAibWlzc2luZyBwUVRMIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKEEuZXNjX2F0YWMpIH4gIm1pc3NpbmcgY2FRVEwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKEEuZXNjX3JuYSkgJiAhaXMubmEoQS5lc2NfcHJvdCkgJiAhaXMubmEoQS5lc2NfYXRhYykgfiAiYWxsIGluIikgKSAtPiBzaWduaWZpY2FudF9wUVRMX2Fubm90MgoKIyBhbGxlbGUgZWZmZWN0IGNvcnJlbGF0aW9ucyBmb3IgZ2VuZXMgd2l0aCBhbGwgdGhyZWUgbWVhc3VyZW1lbnRzCiMgbGV0J3MgZmlsbCBpbiBtaXNzaW5nIGVmZmVjdHMgZmlyc3QgZm9yIGFsbC4KZWZmcy5kZjEgPC0gbGlzdCgpCmVmZnMuZGYyIDwtIGxpc3QoKQplZmZzLmRmMyA8LSBsaXN0KCkKIyBwZGYoKQpzdWJzZXRfcHJvYnMgPC0gZnVuY3Rpb24odGhpc19wcm9icywgdGhpc19jaHJvbSwgdGhpc19tYXJrZXJzKSB7CiAgYXR0IDwtIGF0dHJpYnV0ZXModGhpc19wcm9icykKICBhdHQkbmFtZXMgPC0gdGhpc19jaHJvbQogIGF0dCRpc194X2NociA8LSBzZXROYW1lcyhGQUxTRSwgdGhpc19jaHJvbSkKICBhc3NlcnR0aGF0Ojphc3NlcnRfdGhhdChhbGwodGhpc19tYXJrZXJzICVpbiUgZGltbmFtZXModGhpc19wcm9ic1tbdGhpc19jaHJvbV1dKVtbM11dKSkKICBuZXdwcm9icyA8LSBsaXN0KHRoaXNfcHJvYnNbW3RoaXNfY2hyb21dXVssICwgdGhpc19tYXJrZXJzLCBkcm9wID0gRkFMU0VdKQogIG5hbWVzKG5ld3Byb2JzKSA8LSB0aGlzX2Nocm9tCiAgYXR0cmlidXRlcyhuZXdwcm9icykgPC0gYXR0CiAgbmV3cHJvYnMKfQoKIyBmaWxsIGluIG1pc3NpbmcgZWZmZWN0cyB1c2luZyB0aGUgcHJvdGVpbiBtYXJrZXJzIGZvciBjYVFUTCArIGVRVEwKIyBzbyB3ZSBhcmUgZ2V0dGluZyB0aGUgYWxsZWxlIGVmZmVjdHMgYXQgdGhlIHBRVEwgcGVhayBmb3IgdGhlIG1pc3NpbmcgdmFsdWVzLgpmb3IgKGkgaW4gMTpsZW5ndGgoKHNpZ25pZmljYW50X3BRVExfYW5ub3QyJHF0bF9pZCkpKSB7CiAgI3ByaW50KGkpCiAgdGhpc19jaHJvbSA8LSBzaWduaWZpY2FudF9wUVRMX2Fubm90MiRwZWFrX2NocltpXQogIGdlbmUuaWQgPC0gc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDIkZW5zZW1ibF9nZW5lX2lkW2ldCiAgcGVha19pZCA8LSBzaWduaWZpY2FudF9wUVRMX2Fubm90MiRwZWFrX2lkW2ldCiAgcHJvdGVpbl9pZCA8LSBzaWduaWZpY2FudF9wUVRMX2Fubm90MiRwcm90ZWluX2lkW2ldCiAgCiAgaWYoc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDIkZWZmX3N0YXRbaV0gPT0iYWxsIGluIil7CiAgICBuZXh0CiAgfQogIGlmKCBzaWduaWZpY2FudF9wUVRMX2Fubm90MiRlZmZfc3RhdFtpXSA9PSJtaXNzaW5nIGVRVEwiKXsKICAgIAogICAgdGhpc19tYXJrZXJzIDwtIGMoc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDIkYmVmb3JlLmVzY19wcm90W2ldLHNpZ25pZmljYW50X3BRVExfYW5ub3QyJGFmdGVyLmVzY19wcm90W2ldKQogICAgcHJvYnNfMm1hcmtlciA8LSBzdWJzZXRfcHJvYnModGhyZWV3YXkuc2hhcmVkLnByb2JzLCB0aGlzX2Nocm9tLCB0aGlzX21hcmtlcnMpCiAgICBpZCA8LSB0aHJlZXdheS5zaGFyZWQuZ2VuZXNbIHRocmVld2F5LnNoYXJlZC5nZW5lcyRlbnNlbWJsX2dlbmVfaWQgPT0gZ2VuZS5pZCxdJG5ld19zeW1ib2xbMV0KICAgIGVmZnNfcm5hIDwtIHNjYW4xYmx1cCgKICAgICAgZ2Vub3Byb2JzID0gcHJvYnNfMm1hcmtlciwKICAgICAgcGhlbm8gPSAoc2hhcmVkLnJuYS5kYXRhWywgaWQsIGRyb3AgPSBGQUxTRV0pLAogICAgICBraW5zaGlwID0gdGhyZWV3YXkuc2hhcmVkLmtpbnNoaXBbW3RoaXNfY2hyb21dXSwgCiAgICAgIGFkZGNvdmFyID0gdGhyZWV3YXkuc2hhcmVkLmNvdmFyIAogICAgKQogICAgc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDJbaSwgcGFzdGUwKExFVFRFUlNbMTo4XSwgIi5lc2Nfcm5hIikgXSA8LSBhcy5saXN0KGNvbE1lYW5zKGVmZnNfcm5hKVtMRVRURVJTWzE6OF1dKQogICAgCiAgfQogIAogIGlmKCBzaWduaWZpY2FudF9wUVRMX2Fubm90MiRlZmZfc3RhdFtpXSA9PSJtaXNzaW5nIGNhUVRMIiAmICFpcy5uYShwZWFrX2lkKSl7CiAgIAogICAgdGhpc19tYXJrZXJzIDwtIGMoc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDIkYmVmb3JlLmVzY19wcm90W2ldLHNpZ25pZmljYW50X3BRVExfYW5ub3QyJGFmdGVyLmVzY19wcm90W2ldKQogICAgcHJvYnNfMm1hcmtlciA8LSBzdWJzZXRfcHJvYnModGhyZWV3YXkuc2hhcmVkLnByb2JzLCB0aGlzX2Nocm9tLCB0aGlzX21hcmtlcnMpCiAgICBpZCA8LSB0aHJlZXdheS5zaGFyZWQuZ2VuZXNbIHRocmVld2F5LnNoYXJlZC5nZW5lcyRwZWFrX2lkID09IHBlYWtfaWQsXSRuZXdfc3ltYm9sWzFdCiAgICBlZmZzX2F0YWMgPC0gc2NhbjFibHVwKAogICAgICBnZW5vcHJvYnMgPSBwcm9ic18ybWFya2VyLAogICAgICBwaGVubyA9IChzaGFyZWQuYXRhYy5kYXRhWywgaWQsIGRyb3AgPSBGQUxTRV0pLAogICAgICBraW5zaGlwID0gdGhyZWV3YXkuc2hhcmVkLmtpbnNoaXBbW3RoaXNfY2hyb21dXSwgCiAgICAgIGFkZGNvdmFyID0gdGhyZWV3YXkuc2hhcmVkLmNvdmFyIAogICAgKQogICAgc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDJbaSwgcGFzdGUwKExFVFRFUlNbMTo4XSwgIi5lc2NfYXRhYyIpIF0gPC0gYXMubGlzdChjb2xNZWFucyhlZmZzX2F0YWMpW0xFVFRFUlNbMTo4XV0pCiAgfQogIAogICMgdGhlc2UgYXJlIGFsbCBzaWduaWZpY2FudCBwUVRMIHNvIHRoZXkgYWxsIGhhdmUgZWZmZWN0cyEgCiAgIyBpZiggc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDIkZWZmX3N0YXRbaV0gPT0ibWlzc2luZyBwUVRMIil7CiAgIyAgIAogICMgICB0aGlzX21hcmtlcnMgPC0gYyhzaWduaWZpY2FudF9wUVRMX2Fubm90MiRiZWZvcmUuZXNjX3JuYVtpXSxzaWduaWZpY2FudF9wUVRMX2Fubm90MiRhZnRlci5lc2Nfcm5hW2ldKQogICMgICBwcm9ic18ybWFya2VyIDwtIHN1YnNldF9wcm9icyh0aHJlZXdheS5zaGFyZWQucHJvYnMsIHRoaXNfY2hyb20sIHRoaXNfbWFya2VycykKICAjICAgZWZmc19wcm90IDwtIHNjYW4xYmx1cCgKICAjICAgICBnZW5vcHJvYnMgPSBwcm9ic18ybWFya2VyLAogICMgICAgIHBoZW5vID0gKHNoYXJlZC5wcm90LmRhdGFbLCBpZCwgZHJvcCA9IEZBTFNFXSksCiAgIyAgICAga2luc2hpcCA9IHRocmVld2F5LnNoYXJlZC5raW5zaGlwW1t0aGlzX2Nocm9tXV0sIGFkZGNvdmFyID0gdGhyZWV3YXkuc2hhcmVkLmNvdmFyIAogICMgICApCiAgIyAgIHNpZ25pZmljYW50X3BRVExfYW5ub3QyW2ksIHBhc3RlMChMRVRURVJTWzE6OF0sICIuZXNjX3Byb3QiKSBdIDwtIGFzLmxpc3QoY29sTWVhbnMoZWZmc19wcm90KVtMRVRURVJTWzE6OF1dKQogICMgfQogIAogIAp9CgojIG5vdyBsZXQncyBnZXQgY29ycmVsYXRpb25zLgpzaWduaWZpY2FudF9wUVRMX2Fubm90MiAlPiUKICBtdXRhdGUobG9jYWwgPSBpZmVsc2UoKGxvY2FsLmVzY19ybmEgPT0gVFJVRSB8IGxvY2FsLmVzY19wcm90ID09IFQgfCBsb2NhbC5lc2NfYXRhYyA9PSBUKSwgImxvY2FsIiwgImRpc3RhbnQiKSkgJT4lCiAgI211dGF0ZShxdGxfaWQgPSBwYXN0ZTAoInF0bF8iLCAxOm4oKSkpICU+JQogIHNlbGVjdChjKHBhc3RlMChMRVRURVJTWzE6OF0sICIuZXNjX3JuYSIpLCAicXRsX2lkIikpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygicXRsX2lkIikgJT4lCiAgdCgpIC0+IHNoYXJlZC5ybmEuZWZmcwoKc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDIgJT4lCiAgbXV0YXRlKGxvY2FsID0gaWZlbHNlKChsb2NhbC5lc2Nfcm5hID09IFRSVUUgfCBsb2NhbC5lc2NfcHJvdCA9PSBUIHwgbG9jYWwuZXNjX2F0YWMgPT0gVCksICJsb2NhbCIsICJkaXN0YW50IikpICU+JQogICNtdXRhdGUocXRsX2lkID0gcGFzdGUwKCJxdGxfIiwgMTpuKCkpKSAlPiUKICBzZWxlY3QoYyhwYXN0ZTAoTEVUVEVSU1sxOjhdLCAiLmVzY19wcm90IiksICJxdGxfaWQiKSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJxdGxfaWQiKSAlPiUKICB0KCkgLT4gc2hhcmVkLnByb3QuZWZmcwoKc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDIgJT4lCiAgbXV0YXRlKGxvY2FsID0gaWZlbHNlKChsb2NhbC5lc2NfYXRhYyA9PSBUUlVFIHwgbG9jYWwuZXNjX3JuYSA9PSBUIHwgbG9jYWwuZXNjX2F0YWMgPT0gVCksICJsb2NhbCIsICJkaXN0YW50IikpICU+JQogICNtdXRhdGUocXRsX2lkID0gcGFzdGUwKCJxdGxfIiwgMTpuKCkpKSAlPiUKICBzZWxlY3QoYyhwYXN0ZTAoTEVUVEVSU1sxOjhdLCAiLmVzY19hdGFjIiksICJxdGxfaWQiKSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJxdGxfaWQiKSAlPiUKICB0KCkgLT4gc2hhcmVkLmF0YWMuZWZmcwoKc2lnbmlmaWNhbnRfcFFUTF9jb3Jyc19ybmFfYXRhYyA8LSBjYmluZChzaGFyZWQucm5hLmVmZnMsIHNoYXJlZC5hdGFjLmVmZnMpCmNvbG5hbWVzKHNpZ25pZmljYW50X3BRVExfY29ycnNfcm5hX2F0YWMpIDwtIGMoCiAgcGFzdGUwKGNvbG5hbWVzKHNoYXJlZC5ybmEuZWZmcyksICJfcm5hIiksCiAgcGFzdGUwKGNvbG5hbWVzKHNoYXJlZC5hdGFjLmVmZnMpLCAiX2F0YWMiKQopCmNvcl9ybmFfYXRhYyA8LSByY29ycihzaWduaWZpY2FudF9wUVRMX2NvcnJzX3JuYV9hdGFjLCB0eXBlID0gYygicGVhcnNvbiIpKQpzaWduaWZpY2FudF9wUVRMX2NvcnJzX3JuYV9hdGFjX2RmIDwtIGRhdGEuZnJhbWUoCiAgY29yID0gZGlhZyhjb3Jfcm5hX2F0YWMkclsKICAgIGVuZHNXaXRoKHJvd25hbWVzKGNvcl9ybmFfYXRhYyRyKSwgIl9hdGFjIiksCiAgICBlbmRzV2l0aChjb2xuYW1lcyhjb3Jfcm5hX2F0YWMkciksICJfcm5hIikKICBdKSwKICByb3cgPSByb3duYW1lcyhjb3Jfcm5hX2F0YWMkcilbZW5kc1dpdGgocm93bmFtZXMoY29yX3JuYV9hdGFjJHIpLCAiX2F0YWMiKV0sCiAgY29sdW1uID0gY29sbmFtZXMoY29yX3JuYV9hdGFjJHIpW2VuZHNXaXRoKGNvbG5hbWVzKGNvcl9ybmFfYXRhYyRyKSwgIl9ybmEiKV0sCiAgcF92YWwgPSBkaWFnKGNvcl9ybmFfYXRhYyRQWwogICAgZW5kc1dpdGgocm93bmFtZXMoY29yX3JuYV9hdGFjJFApLCAiX2F0YWMiKSwKICAgIGVuZHNXaXRoKGNvbG5hbWVzKGNvcl9ybmFfYXRhYyRQKSwgIl9ybmEiKQogIF0pLAogIG4gPSBkaWFnKGNvcl9ybmFfYXRhYyRuWwogICAgZW5kc1dpdGgocm93bmFtZXMoY29yX3JuYV9hdGFjJG4pLCAiX2F0YWMiKSwKICAgIGVuZHNXaXRoKGNvbG5hbWVzKGNvcl9ybmFfYXRhYyRuKSwgIl9ybmEiKQogIF0pCikgJT4lIAogIG11dGF0ZShxdGxfaWQgPSBnc3ViKCJfYXRhYyIsICIiLCByb3cpKSAlPiUKICAjbXV0YXRlKHBfYWRqID0gcC5hZGp1c3QocF92YWwsICJCSCIpKSAlPiUKICBhcnJhbmdlKGRlc2MoYWJzKGNvcikpKSAlPiUKICBsZWZ0X2pvaW4oLiwgKHNpZ25pZmljYW50X3BRVExfYW5ub3QyICU+JQogICAgbXV0YXRlKGxvY2FsID0gaWZlbHNlKChsb2NhbC5lc2Nfcm5hID09IFRSVUUgfCBsb2NhbC5lc2NfYXRhYyA9PSBUKSwgImxvY2FsIiwgImRpc3RhbnQiKSkgKQogICAgKQoKCnNpZ25pZmljYW50X3BRVExfY29ycnNfcm5hX3Byb3QgPC0gY2JpbmQoc2hhcmVkLnJuYS5lZmZzLCBzaGFyZWQucHJvdC5lZmZzKQpjb2xuYW1lcyhzaWduaWZpY2FudF9wUVRMX2NvcnJzX3JuYV9wcm90KSA8LSBjKAogIHBhc3RlMChjb2xuYW1lcyhzaGFyZWQucm5hLmVmZnMpLCAiX3JuYSIpLAogIHBhc3RlMChjb2xuYW1lcyhzaGFyZWQucHJvdC5lZmZzKSwgIl9wcm90IikKKQpjb3Jfcm5hX3Byb3QgPC0gcmNvcnIoc2lnbmlmaWNhbnRfcFFUTF9jb3Jyc19ybmFfcHJvdCwgdHlwZSA9IGMoInBlYXJzb24iKSkKc2lnbmlmaWNhbnRfcFFUTF9jb3Jyc19ybmFfcHJvdF9kZiA8LSBkYXRhLmZyYW1lKAogIGNvciA9IGRpYWcoY29yX3JuYV9wcm90JHJbCiAgICBlbmRzV2l0aChyb3duYW1lcyhjb3Jfcm5hX3Byb3QkciksICJfcHJvdCIpLAogICAgZW5kc1dpdGgoY29sbmFtZXMoY29yX3JuYV9wcm90JHIpLCAiX3JuYSIpCiAgXSksCiAgcm93ID0gcm93bmFtZXMoY29yX3JuYV9wcm90JHIpW2VuZHNXaXRoKHJvd25hbWVzKGNvcl9ybmFfcHJvdCRyKSwgIl9wcm90IildLAogIGNvbHVtbiA9IGNvbG5hbWVzKGNvcl9ybmFfcHJvdCRyKVtlbmRzV2l0aChjb2xuYW1lcyhjb3Jfcm5hX3Byb3QkciksICJfcm5hIildLAogIHBfdmFsID0gZGlhZyhjb3Jfcm5hX3Byb3QkUFsKICAgIGVuZHNXaXRoKHJvd25hbWVzKGNvcl9ybmFfcHJvdCRQKSwgIl9wcm90IiksCiAgICBlbmRzV2l0aChjb2xuYW1lcyhjb3Jfcm5hX3Byb3QkUCksICJfcm5hIikKICBdKSwKICBuID0gZGlhZyhjb3Jfcm5hX3Byb3QkblsKICAgIGVuZHNXaXRoKHJvd25hbWVzKGNvcl9ybmFfcHJvdCRuKSwgIl9wcm90IiksCiAgICBlbmRzV2l0aChjb2xuYW1lcyhjb3Jfcm5hX3Byb3QkbiksICJfcm5hIikKICBdKQopICU+JQogIG11dGF0ZShxdGxfaWQgPSBnc3ViKCJfcHJvdCIsICIiLCByb3cpKSAlPiUKICBtdXRhdGUocF9hZGogPSBwLmFkanVzdChwX3ZhbCwgbWV0aG9kID0gIkJIIikpICU+JQogIGFycmFuZ2UoZGVzYyhhYnMoY29yKSkpICU+JQogIGxlZnRfam9pbiguLCAoc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDIgJT4lCiAgICBtdXRhdGUobG9jYWwgPSBpZmVsc2UoKGxvY2FsLmVzY19ybmEgPT0gVFJVRSB8IGxvY2FsLmVzY19wcm90ID09IFQpLCAibG9jYWwiLCAiZGlzdGFudCIpKSApCiAgICApCgoKc2lnbmlmaWNhbnRfcFFUTF9jb3Jyc19wcm90X2F0YWMgPC0gY2JpbmQoc2hhcmVkLnByb3QuZWZmcywgc2hhcmVkLmF0YWMuZWZmcykKY29sbmFtZXMoc2lnbmlmaWNhbnRfcFFUTF9jb3Jyc19wcm90X2F0YWMpIDwtIGMoCiAgcGFzdGUwKGNvbG5hbWVzKHNoYXJlZC5wcm90LmVmZnMpLCAiX3Byb3QiKSwKICBwYXN0ZTAoY29sbmFtZXMoc2hhcmVkLmF0YWMuZWZmcyksICJfYXRhYyIpCikKY29yX3Byb3RfYXRhYyA8LSByY29ycihzaWduaWZpY2FudF9wUVRMX2NvcnJzX3Byb3RfYXRhYywgdHlwZSA9IGMoInBlYXJzb24iKSkKc2lnbmlmaWNhbnRfcFFUTF9jb3Jyc19wcm90X2F0YWNfZGYgPC0gZGF0YS5mcmFtZSgKICBjb3IgPSBkaWFnKGNvcl9wcm90X2F0YWMkclsKICAgIGVuZHNXaXRoKHJvd25hbWVzKGNvcl9wcm90X2F0YWMkciksICJfYXRhYyIpLAogICAgZW5kc1dpdGgoY29sbmFtZXMoY29yX3Byb3RfYXRhYyRyKSwgIl9wcm90IikKICBdKSwKICByb3cgPSByb3duYW1lcyhjb3JfcHJvdF9hdGFjJHIpW2VuZHNXaXRoKHJvd25hbWVzKGNvcl9wcm90X2F0YWMkciksICJfYXRhYyIpXSwKICBjb2x1bW4gPSBjb2xuYW1lcyhjb3JfcHJvdF9hdGFjJHIpW2VuZHNXaXRoKGNvbG5hbWVzKGNvcl9wcm90X2F0YWMkciksICJfcHJvdCIpXSwKICBwX3ZhbCA9IGRpYWcoY29yX3Byb3RfYXRhYyRQWwogICAgZW5kc1dpdGgocm93bmFtZXMoY29yX3Byb3RfYXRhYyRQKSwgIl9hdGFjIiksCiAgICBlbmRzV2l0aChjb2xuYW1lcyhjb3JfcHJvdF9hdGFjJFApLCAiX3Byb3QiKQogIF0pLAogIG4gPSBkaWFnKGNvcl9wcm90X2F0YWMkblsKICAgIGVuZHNXaXRoKHJvd25hbWVzKGNvcl9wcm90X2F0YWMkbiksICJfYXRhYyIpLAogICAgZW5kc1dpdGgoY29sbmFtZXMoY29yX3Byb3RfYXRhYyRuKSwgIl9wcm90IikKICBdKQopICU+JQogIG11dGF0ZShxdGxfaWQgPSBnc3ViKCJfYXRhYyIsICIiLCByb3cpKSAlPiUKICBtdXRhdGUocF9hZGogPSBwLmFkanVzdChwX3ZhbCwgbWV0aG9kID0gIkJIIikpICU+JQogIGFycmFuZ2UoZGVzYyhhYnMoY29yKSkpICU+JQogIGxlZnRfam9pbiguLCAoc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDIgJT4lCiAgICBtdXRhdGUobG9jYWwgPSBpZmVsc2UoKGxvY2FsLmVzY19wcm90ID09IFRSVUUgfCBsb2NhbC5lc2NfYXRhYyA9PSBUKSwgImxvY2FsIiwgImRpc3RhbnQiKSkgKQogICAgKQoKCiMgbGV0J3MgYWRkIGNvcnJlbGF0aW9ucyBiYWNrIHRvIHRoZSB0YWJsZToKCnNpZ25pZmljYW50X3BRVExfYW5ub3QyICU+JSAKICBmdWxsX2pvaW4oIAogICAgIHNpZ25pZmljYW50X3BRVExfY29ycnNfcHJvdF9hdGFjX2RmICU+JSAKICAgICAgc2VsZWN0KCBjb3JfYXRhY19wcm90ID0gY29yLCBxdGxfaWQpCiAgICApICU+JSAKICBmdWxsX2pvaW4oCiAgICAgc2lnbmlmaWNhbnRfcFFUTF9jb3Jyc19ybmFfYXRhY19kZiAlPiUgCiAgICAgIHNlbGVjdCggY29yX2F0YWNfcm5hID0gY29yLCBxdGxfaWQpCiAgKSAlPiUgCiAgZnVsbF9qb2luKAogICAgc2lnbmlmaWNhbnRfcFFUTF9jb3Jyc19ybmFfcHJvdF9kZiAlPiUgCiAgICAgIHNlbGVjdCggY29yX3JuYV9wcm90ID0gY29yLCBxdGxfaWQpCiAgKSAtPiAgc2lnbmlmaWNhbnRfcFFUTF93Y29ycgoKCiMgTGV0J3Mgc2F2ZSBlYWNoIGNhdGVnb3J5IHRvIGluZGl2aWR1YWwgb2JqZWN0cyBhbmQgZmlsdGVyIGFjYyB0byB0aHJlc2hvbGRzCiMgYWxsIHRoZSB1bmlxdWUgcFFUTCB3aXRoIGNvcnJlbGF0aW9ucy4gCnNpZ25pZmljYW50X3BRVExfd2NvcnIgJT4lIAogIGZpbHRlciggbWF0Y2ggJWluJSBjKCJ1bmlxdWUgcFFUTCIpKSAtPiB1bmlxLnBRVEwud2NvcnIKCiMgc2hhcmVkIGVRVEwvcFFUTCB3aXRoIGNvcnJlbGF0aW9ucwojIG5vdGUgdGhhdCBhdGFjLXNlcSBwZWFrIGFubm90YXRpb25zIHdpbGwgbGVhZCB0byByZXBldGl0aW9ucywgbmVlZCB0byBkcm9wIGF0YWMgY29sdW1ucyB0byBnZXQgZGlzdGluY3QgZVFUTC9wUVRMCnNpZ25pZmljYW50X3BRVExfd2NvcnIgJT4lIAogIGZpbHRlciggbWF0Y2ggJWluJSBjKCJzaGFyZWQgZS9wUVRMIikpIC0+IGVRVEwucFFUTC53Y29ycgoKIyBzaGFyZWQgY2FRVEwvcFFUTCB3aXRoIGNvcnJlbGF0aW9ucwpzaWduaWZpY2FudF9wUVRMX3djb3JyICU+JSAKICBmaWx0ZXIoIG1hdGNoICVpbiUgYygic2hhcmVkIGNhL3BRVEwiKSkgJT4lIAogIGdyb3VwX2J5KHByb3RlaW5faWQsIHBlYWtfY2hyLCBsb2QuZXNjX3Byb3QsIG1hdGNoKSAlPiUgCiAgc2xpY2VfbWF4KCBhYnMoY29yX2F0YWNfcHJvdCkpICAlPiUgIyB0YWtlIHRoZSBhdGFjIHBlYWtzIHdpdGggaGlnaGVzdCBjb3JyZWxhdGlvbiwgZ2V0cyByaWQgb2ZmIE5BcwogIHVuZ3JvdXAoKSAgLT4gY2FRVEwucFFUTC53Y29ycgoKIyBzaGFyZWQgY2EvZS9wUVRMCiMga2VlcGluZyB0aGUgYXRhYy1zZXEgcGVhayB3aXRoIHRoZSBoaWdoZXN0IGNvcnJlbGF0aW9uIG9ubHkKc2lnbmlmaWNhbnRfcFFUTF93Y29yciAlPiUgCiAgZmlsdGVyKCBtYXRjaCAlaW4lIGMoInNoYXJlZCBjYS9lL3BRVEwiKSApICAgJT4lIAogIGdyb3VwX2J5KHByb3RlaW5faWQsIHBlYWtfY2hyLCBsb2QuZXNjX3Byb3QsIG1hdGNoKSAlPiUgCiAgc2xpY2VfbWF4KCBhYnMoY29yX2F0YWNfcHJvdCkpICAlPiUgIyB0YWtlIHRoZSBhdGFjIHBlYWtzIHdpdGggaGlnaGVzdCBjb3JyZWxhdGlvbiwgZ2V0cyByaWQgb2ZmIE5BcwogIHVuZ3JvdXAoKSAgLT4gdGhyZWV3YXkuc2hhcmVkLnBRVEwud2NvcnIKCgojIG5vdyBJIHdpbGwgdXBkYXRlIHRoZSBwUVRMIGNsYXNzaWZpY2F0aW9ucwojIGdldCB1bmlxdWUgcFFUTAp1bmlxLnBRVEwud2NvcnIgJT4lIAogIHNlbGVjdCggcHJvdGVpbl9pZCwgbG9kLmVzY19wcm90LCBwZWFrX2NocikgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIHJiaW5kKAogICAgZVFUTC5wUVRMLndjb3JyICU+JSAKICAgICAgZmlsdGVyKCBhYnMoY29yX3JuYV9wcm90KSA8IDAuNSkgJT4lIAogICAgICBzZWxlY3QoIHByb3RlaW5faWQsIHBlYWtfY2hyLCBsb2QuZXNjX3Byb3QpICU+JQogICAgICBkaXN0aW5jdCgpCiAgKSAlPiUgCiAgcmJpbmQoCiAgICBjYVFUTC5wUVRMLndjb3JyICU+JSAKICAgICAgZmlsdGVyKCBhYnMoY29yX2F0YWNfcHJvdCkgPCAwLjUpICU+JSAKICAgICAgc2VsZWN0KCBwcm90ZWluX2lkLCBwZWFrX2NociwgbG9kLmVzY19wcm90KSAlPiUKICAgICAgZGlzdGluY3QoKSAKICApICU+JSAKICByYmluZCgKICAgIHRocmVld2F5LnNoYXJlZC5wUVRMLndjb3JyICU+JSAKICAgICAgZmlsdGVyKCBhYnMoY29yX2F0YWNfcHJvdCkgPCAwLjUgJiBhYnMoY29yX3JuYV9wcm90KSA8MC41ICkgJT4lIAogICAgICBzZWxlY3QoIHByb3RlaW5faWQsIHBlYWtfY2hyLCBsb2QuZXNjX3Byb3QpICU+JQogICAgICBkaXN0aW5jdCgpIAogICkgJT4lIAogIG11dGF0ZSggbWF0Y2ggPSAidW5pcXVlIHBRVEwiKSAtPiB1bmlxdWVfcFFUTAojIGdldCBzaGFyZWQgZVFUTC9wUVRMIAplUVRMLnBRVEwud2NvcnIgJT4lIAogIGZpbHRlciggYWJzKGNvcl9ybmFfcHJvdCkgPj0gMC41KSAlPiUgIyBmaWx0ZXIgb25lcyB0aGF0IG1vdmVkIHRvIHVuaXF1ZSBwUVRMCiAgc2VsZWN0KCBwcm90ZWluX2lkLCBsb2QuZXNjX3Byb3QsIHBlYWtfY2hyKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgcmJpbmQoIAogICAgdGhyZWV3YXkuc2hhcmVkLnBRVEwud2NvcnIgJT4lICMgbW92ZSBvbmVzIHdpdGggYWJzKGNvcik8MC41IGZyb20gc2hhcmVkIGNhL2UvcFFUTAogICAgICBmaWx0ZXIoIGFicyhjb3JfYXRhY19wcm90KSA8IDAuNSAmIGFicyhjb3Jfcm5hX3Byb3QpID49IDAuNSApICU+JSAKICAgICAgc2VsZWN0KCBwcm90ZWluX2lkLCBwZWFrX2NociwgbG9kLmVzY19wcm90KSAlPiUKICAgICAgZGlzdGluY3QoKSAKICApICU+JSAKICBtdXRhdGUoIG1hdGNoID0gInNoYXJlZCBlL3BRVEwiKSAtPiBzaGFyZWRfZVFUTF9wUVRMCiMgZ2V0IHNoYXJlZCBjYVFUTC9wUVRMIApjYVFUTC5wUVRMLndjb3JyICU+JSAKICBmaWx0ZXIoIGFicyhjb3JfYXRhY19wcm90KSA+PTAuNSkgJT4lICMgZmlsdGVyIG9uZXMgdGhhdCBtb3ZlZCB0byB1bmlxdWUgcFFUTAogIHNlbGVjdCggcHJvdGVpbl9pZCwgbG9kLmVzY19wcm90LCBwZWFrX2NocikgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIHJiaW5kKAogICAgdGhyZWV3YXkuc2hhcmVkLnBRVEwud2NvcnIgJT4lICAjIG1vdmUgb25lcyB3aXRoIGFicyhjb3IpPDAuNSBmcm9tIHNoYXJlZCBjYS9lL3BRVEwKICAgICAgZmlsdGVyKCBhYnMoY29yX2F0YWNfcHJvdCkgPj0gMC41ICYgYWJzKGNvcl9ybmFfcHJvdCkgPCAwLjUgKSAlPiUgCiAgICAgIHNlbGVjdCggcHJvdGVpbl9pZCwgcGVha19jaHIsIGxvZC5lc2NfcHJvdCkgJT4lCiAgICAgIGRpc3RpbmN0KCkgCiAgKSAlPiUgCiAgbXV0YXRlKCBtYXRjaCA9ICJzaGFyZWQgY2EvcFFUTCIpIC0+IHNoYXJlZF9jYVFUTF9wUVRMCiMgZ2V0IHNoYXJlZCBjYS9lL3BRVEwgCnRocmVld2F5LnNoYXJlZC5wUVRMLndjb3JyICU+JQogIGZpbHRlciggYWJzKGNvcl9ybmFfcHJvdCkgPj0gMC41ICYgYWJzKGNvcl9hdGFjX3Byb3QpID49IDAuNSkgJT4lCiAgc2VsZWN0KHByb3RlaW5faWQsIHBlYWtfY2hyLCBsb2QuZXNjX3Byb3QpICU+JQogIGRpc3RpbmN0KCkgJT4lIAogIG11dGF0ZSggbWF0Y2ggPSAic2hhcmVkIGNhL2UvcFFUTCIpIC0+IHNoYXJlZF9wUVRMCiAgCnNpZ25pZmljYW50X3BRVExfYW5ub3RfdXBkYXRlZCA8LSByYmluZCgKICBzaGFyZWRfcFFUTCwgCiAgdW5pcXVlX3BRVEwsCiAgc2hhcmVkX2NhUVRMX3BRVEwsIAogIHNoYXJlZF9lUVRMX3BRVEwKKSAlPiUgCiAgbGVmdF9qb2luKCBzZWxlY3Qoc2lnbmlmaWNhbnRfcFFUTF9hbm5vdDIsIC1tYXRjaCwgLW1hdGNoX2FsbCwgLWVmZl9zdGF0KQogICkgJT4lIAogICAgZnVsbF9qb2luKCAKICAgICBzaWduaWZpY2FudF9wUVRMX2NvcnJzX3Byb3RfYXRhY19kZiAlPiUgCiAgICAgIHNlbGVjdCggY29yX2F0YWNfcHJvdCA9IGNvciwgcXRsX2lkKQogICAgKSAlPiUgCiAgZnVsbF9qb2luKAogICAgIHNpZ25pZmljYW50X3BRVExfY29ycnNfcm5hX2F0YWNfZGYgJT4lIAogICAgICBzZWxlY3QoIGNvcl9hdGFjX3JuYSA9IGNvciwgcXRsX2lkKQogICkgJT4lIAogIGZ1bGxfam9pbigKICAgIHNpZ25pZmljYW50X3BRVExfY29ycnNfcm5hX3Byb3RfZGYgJT4lIAogICAgICBzZWxlY3QoIGNvcl9ybmFfcHJvdCA9IGNvciwgcXRsX2lkKQogICkgJT4lIAogIGxlZnRfam9pbigKICAgIHBlYWtzLnRocmVld2F5LnNoYXJlZC5nZW5lcyAlPiUgc2VsZWN0KCBwcm90ZWluX2lkLG1naV9zeW1ib2wsIGN1bXN1bV9icF9nZW5lKSAlPiUgZGlzdGluY3QoKQogICkgCiAgCnJiaW5kKAogIHNoYXJlZF9wUVRMLCAKICB1bmlxdWVfcFFUTCwKICBzaGFyZWRfY2FRVExfcFFUTCwgCiAgc2hhcmVkX2VRVExfcFFUTAopICU+JQogIGxlZnRfam9pbiggc2lnbmlmaWNhbnRfcFFUTF9hbm5vdCAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChwcm90ZWluX2lkLCBwZWFrX2NociwgbG9kLmVzY19wcm90LCBsb2NhbCApCiAgICAgICAgICAgICApICU+JSAKICBncm91cF9ieShtYXRjaCkgJT4lICMgc3VtbWFyaXplKG4gPSBuX2Rpc3RpbmN0KHByb3RlaW5faWQpKQogIGNvdW50KG1hdGNoLCBsb2NhbCkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUoIGxvY2FsID0gaWZlbHNlKCBsb2NhbCwgImxvY2FsIiwgImRpc3RhbnQiKSkgJT4lIAogIHBpdm90X3dpZGVyKAogICAgaWRfY29scyA9IG1hdGNoLG5hbWVzX2Zyb20gPSAibG9jYWwiLCB2YWx1ZXNfZnJvbSA9ICJuIgogICkgJT4lIAogIG11dGF0ZSggbG9jYWwgPSByb3VuZCgxMDAqbG9jYWwvKHN1bShsb2NhbCkpKSwKICAgICAgICAgIGRpc3RhbnQgPSByb3VuZCgxMDAqZGlzdGFudC8oc3VtKGRpc3RhbnQpKSkKICApICU+JSAKICBzZWxlY3QoIGBPdmVybGFwYD1tYXRjaCAsIAogICAgICAgICAgYGxvY2FsICglKWAgPSBsb2NhbCwgCiAgICAgICAgICBgZGlzdGFudCAoJSlgPSBkaXN0YW50KSAlPiUgCiAgbXV0YXRlKAogICAgb3JkZXIgPSBjYXNlX3doZW4oIE92ZXJsYXAgPT0ic2hhcmVkIGNhL2UvcFFUTCJ+MSwKICAgICAgICAgICAgICAgICAgICAgICBPdmVybGFwID09InNoYXJlZCBlL3BRVEwifjIsCiAgICAgICAgICAgICAgICAgICAgICAgT3ZlcmxhcCA9PSAidW5pcXVlIHBRVEwifjMsCiAgICAgICAgICAgICAgICAgICAgICAgT3ZlcmxhcCA9PSJzaGFyZWQgY2EvcFFUTCJ+NCkKICApICU+JSAKICBhcnJhbmdlKG9yZGVyKSAlPiUgCiAgc2VsZWN0KC1vcmRlcikgJT4lIAogIERUOjpkYXRhdGFibGUoLiwKICAgICAgICAgICAgICAgIGV4dGVuc2lvbnMgPSAnQnV0dG9ucycsCiAgICAgICAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICNmaWx0ZXI9InRvcCIsCiAgICAgICAgICAgICAgICBvcHRpb25zID0gbGlzdChkb20gPSAndCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygnY29weScpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFnZUxlbmd0aCA9IDUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsWD0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkKCgpgYGAKCgoK

A work by Selcan Aydin

selcan.aydin@jax.org